summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/api/test-current.txt26
-rw-r--r--core/java/android/app/NotificationChannel.java3
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java13
-rw-r--r--core/java/android/hardware/devicestate/DeviceState.java142
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateManager.java74
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java66
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateRequest.java8
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateUtil.java76
-rw-r--r--core/java/android/hardware/display/DisplayManager.java16
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java17
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl4
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java24
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java60
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java25
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java21
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig7
-rw-r--r--packages/SystemUI/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt29
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt11
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt53
-rw-r--r--packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt2
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml1
-rw-r--r--packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml146
-rw-r--r--packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml130
-rw-r--r--packages/SystemUI/res/layout/app_clips_screenshot.xml2
-rw-r--r--packages/SystemUI/res/layout/biometric_prompt_button_bar.xml91
-rw-r--r--packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml191
-rw-r--r--packages/SystemUI/res/layout/long_screenshot.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt137
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LogConfig.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/CropView.java)15
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageLoader.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/ImageLoader.java)29
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTile.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTileSet.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotActivity.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java)30
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotData.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotData.java)5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/MagnifierView.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java)24
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/ScrollCaptureClient.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java)5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/ScrollCaptureController.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java)14
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/TiledImageDrawable.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java17
-rw-r--r--packages/SystemUI/tests/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java)4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureClientTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java)8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureFrameworkSmokeTest.java)4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java (renamed from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java)4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt142
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java37
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/jank/InteractionJankMonitorKosmos.kt19
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeScrollCaptureConnection.java (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java)4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeSession.java (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/FakeSession.java)6
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerService.java13
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java66
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java24
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java16
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java22
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig12
-rw-r--r--services/core/java/com/android/server/display/mode/BaseModeRefreshRateVote.java4
-rw-r--r--services/core/java/com/android/server/display/mode/CombinedVote.java4
-rw-r--r--services/core/java/com/android/server/display/mode/DisableRefreshRateSwitchingVote.java4
-rw-r--r--services/core/java/com/android/server/display/mode/DisplayModeDirector.java146
-rw-r--r--services/core/java/com/android/server/display/mode/ProximitySensorObserver.java138
-rw-r--r--services/core/java/com/android/server/display/mode/RefreshRateVote.java6
-rw-r--r--services/core/java/com/android/server/display/mode/SizeVote.java4
-rw-r--r--services/core/java/com/android/server/display/mode/SupportedModesVote.java69
-rw-r--r--services/core/java/com/android/server/display/mode/SupportedRefreshRatesVote.java94
-rw-r--r--services/core/java/com/android/server/display/mode/SystemRequestObserver.java139
-rw-r--r--services/core/java/com/android/server/display/mode/Vote.java34
-rw-r--r--services/core/java/com/android/server/display/mode/VoteSummary.java47
-rw-r--r--services/core/java/com/android/server/display/mode/VotesStatsReporter.java8
-rw-r--r--services/core/java/com/android/server/display/mode/VotesStorage.java39
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java12
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/core/jni/com_android_server_UsbDeviceManager.cpp29
-rw-r--r--services/core/xsd/display-device-config/display-device-config.xsd28
-rw-r--r--services/core/xsd/display-device-config/schema/current.txt21
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java31
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java5
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java29
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt6
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/ProximitySensorObserverTest.java127
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt6
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SupportedModesVoteTest.kt23
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SupportedRefreshRatesVoteTest.kt72
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt212
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt88
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java48
-rw-r--r--services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java3
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java10
131 files changed, 2564 insertions, 1314 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 78ac7749fc89..0ab477293bae 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5006,7 +5006,7 @@ package android.hardware.devicestate {
}
public static interface DeviceStateManager.DeviceStateCallback {
- method public default void onDeviceStateChanged(@NonNull android.hardware.devicestate.DeviceState);
+ method public void onDeviceStateChanged(@NonNull android.hardware.devicestate.DeviceState);
method public default void onSupportedStatesChanged(@NonNull java.util.List<android.hardware.devicestate.DeviceState>);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index bc45a76d861b..c1af719e91c9 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1625,25 +1625,37 @@ package android.hardware.camera2.params {
package android.hardware.devicestate {
@FlaggedApi("android.hardware.devicestate.feature.flags.device_state_property_api") public final class DeviceState {
+ ctor public DeviceState(@NonNull android.hardware.devicestate.DeviceState.Configuration);
field public static final int PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST = 8; // 0x8
}
+ public static final class DeviceState.Configuration implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getIdentifier();
+ method @NonNull public String getName();
+ method @NonNull public java.util.Set<java.lang.Integer> getPhysicalProperties();
+ method @NonNull public java.util.Set<java.lang.Integer> getSystemProperties();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.devicestate.DeviceState.Configuration> CREATOR;
+ }
+
+ public static final class DeviceState.Configuration.Builder {
+ ctor public DeviceState.Configuration.Builder(int, @NonNull String);
+ method @NonNull public android.hardware.devicestate.DeviceState.Configuration build();
+ method @NonNull public android.hardware.devicestate.DeviceState.Configuration.Builder setPhysicalProperties(@NonNull java.util.Set<java.lang.Integer>);
+ method @NonNull public android.hardware.devicestate.DeviceState.Configuration.Builder setSystemProperties(@NonNull java.util.Set<java.lang.Integer>);
+ }
+
@FlaggedApi("android.hardware.devicestate.feature.flags.device_state_property_api") public final class DeviceStateManager {
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelBaseStateOverride();
method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void cancelStateRequest();
- method @Deprecated @NonNull public int[] getSupportedStates();
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestBaseStateOverride(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
+ field public static final int INVALID_DEVICE_STATE_IDENTIFIER = -1; // 0xffffffff
field public static final int MAXIMUM_DEVICE_STATE_IDENTIFIER = 10000; // 0x2710
field public static final int MINIMUM_DEVICE_STATE_IDENTIFIER = 0; // 0x0
}
- public static interface DeviceStateManager.DeviceStateCallback {
- method @Deprecated public default void onBaseStateChanged(int);
- method @Deprecated public void onStateChanged(int);
- method @Deprecated public default void onSupportedStatesChanged(@NonNull int[]);
- }
-
public final class DeviceStateRequest {
method public int getFlags();
method public int getState();
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 9f2e4739e8e6..7c803ebde384 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -776,7 +776,8 @@ public final class NotificationChannel implements Parcelable {
/**
* Whether or not notifications posted to this channel can bypass the Do Not Disturb
- * {@link NotificationManager#INTERRUPTION_FILTER_PRIORITY} mode.
+ * {@link NotificationManager#INTERRUPTION_FILTER_PRIORITY} mode when the active policy allows
+ * priority channels to bypass notification filtering.
*/
public boolean canBypassDnd() {
return mBypassDnd;
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index d2e4a614202f..b43a900bec80 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -47,6 +47,7 @@ import android.hardware.camera2.params.StreamConfiguration;
import android.hardware.camera2.utils.CameraIdAndSessionConfiguration;
import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
import android.hardware.camera2.utils.ExceptionUtils;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManager;
import android.os.Binder;
@@ -204,14 +205,12 @@ public final class CameraManager {
mDeviceStateListeners.add(new WeakReference<>(listener));
}
+ @SuppressWarnings("FlaggedApi")
@Override
- public final void onBaseStateChanged(int state) {
- handleStateChange(state);
- }
-
- @Override
- public final void onStateChanged(int state) {
- handleStateChange(state);
+ public void onDeviceStateChanged(DeviceState state) {
+ // Suppressing the FlaggedAPI warning as this specific API isn't new, just moved to
+ // system API which requires it to be flagged.
+ handleStateChange(state.getIdentifier());
}
}
diff --git a/core/java/android/hardware/devicestate/DeviceState.java b/core/java/android/hardware/devicestate/DeviceState.java
index 76888f338615..b214da227a2d 100644
--- a/core/java/android/hardware/devicestate/DeviceState.java
+++ b/core/java/android/hardware/devicestate/DeviceState.java
@@ -52,78 +52,6 @@ import java.util.Set;
@FlaggedApi(android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_PROPERTY_API)
public final class DeviceState {
/**
- * Flag that indicates override requests should be cancelled when this device state becomes the
- * base device state.
- * @hide
- * @deprecated use {@link #PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS}
- */
- @Deprecated
- public static final int FLAG_CANCEL_OVERRIDE_REQUESTS = 1 << 0;
-
- /**
- * Flag that indicates this device state is inaccessible for applications to be placed in. This
- * could be a device-state where the {@link Display#DEFAULT_DISPLAY} is not enabled.
- * @hide
- * @deprecated use {@link #PROPERTY_APP_INACCESSIBLE}
- */
- @Deprecated
- public static final int FLAG_APP_INACCESSIBLE = 1 << 1;
-
- /**
- * Some device states can be both entered through a physical configuration as well as emulation
- * through {@link DeviceStateManager#requestState}, while some states can only be entered
- * through emulation and have no physical configuration to match.
- *
- * This flag indicates that the corresponding state can only be entered through emulation.
- * @hide
- * @deprecated use {@link #PROPERTY_EMULATED_ONLY}
- */
- @Deprecated
- public static final int FLAG_EMULATED_ONLY = 1 << 2;
-
- /**
- * This flag indicates that the corresponding state should be automatically canceled when the
- * requesting app is no longer on top. The app is considered not on top when (1) the top
- * activity in the system is from a different app, (2) the device is in sleep mode, or
- * (3) the keyguard shows up.
- * @hide
- * @deprecated use {@link #PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP}
- */
- @Deprecated
- public static final int FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP = 1 << 3;
-
- /**
- * This flag indicates that the corresponding state should be disabled when the device is
- * overheating and reaching the critical status.
- * @hide
- * @deprecated use {@link #PROPERTY_POLICY_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL}
- */
- @Deprecated
- public static final int FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL = 1 << 4;
-
- /**
- * This flag indicates that the corresponding state should be disabled when power save mode
- * is enabled.
- * @hide
- * @deprecated use {@link #PROPERTY_POLICY_UNSUPPORTED_WHEN_POWER_SAVE_MODE}
- */
- @Deprecated
- public static final int FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE = 1 << 5;
-
- /** @hide */
- @IntDef(prefix = {"FLAG_"}, flag = true, value = {
- FLAG_CANCEL_OVERRIDE_REQUESTS,
- FLAG_APP_INACCESSIBLE,
- FLAG_EMULATED_ONLY,
- FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP,
- FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL,
- FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE
- })
- @Deprecated
- @Retention(RetentionPolicy.SOURCE)
- public @interface DeviceStateFlags {}
-
- /**
* Property that indicates that a fold-in style foldable device is currently in a fully closed
* configuration.
*/
@@ -302,42 +230,11 @@ public final class DeviceState {
@NonNull
private final DeviceState.Configuration mDeviceStateConfiguration;
- @DeviceStateFlags
- private final int mFlags;
-
/** @hide */
+ @TestApi
public DeviceState(@NonNull DeviceState.Configuration deviceStateConfiguration) {
Objects.requireNonNull(deviceStateConfiguration, "Device StateConfiguration is null");
mDeviceStateConfiguration = deviceStateConfiguration;
- mFlags = 0;
- }
-
- /** @hide */
- public DeviceState(
- @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
- MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier,
- @NonNull String name,
- @NonNull Set<@DeviceStateProperties Integer> properties) {
- mDeviceStateConfiguration = new DeviceState.Configuration(identifier, name, properties,
- Collections.emptySet());
- mFlags = 0;
- }
-
- /**
- * @deprecated Deprecated in favor of {@link #DeviceState(int, String, Set)}
- * @hide
- */
- // TODO(b/325124054): Make non-default and remove deprecated callback methods.
- @Deprecated
- public DeviceState(
- @IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to =
- MAXIMUM_DEVICE_STATE_IDENTIFIER) int identifier,
- @NonNull String name,
- @DeviceStateFlags int flags) {
-
- mDeviceStateConfiguration = new DeviceState.Configuration(identifier, name,
- Collections.emptySet(), Collections.emptySet());
- mFlags = flags;
}
/** Returns the unique identifier for the device state. */
@@ -352,17 +249,6 @@ public final class DeviceState {
return mDeviceStateConfiguration.getName();
}
- /**
- * @hide
- * @deprecated in favor of {@link #hasProperty(int)} method
- */
- // TODO(b/325124054): Make non-default and remove deprecated callback methods.
- @Deprecated
- @DeviceStateFlags
- public int getFlags() {
- return mFlags;
- }
-
@Override
public String toString() {
return "DeviceState{" + "identifier=" + mDeviceStateConfiguration.getIdentifier()
@@ -388,16 +274,6 @@ public final class DeviceState {
return Objects.hash(mDeviceStateConfiguration);
}
- /** Checks if a specific flag is set
- * @hide
- * @deprecated in favor of {@link #hasProperty(int)}
- */
- // TODO(b/325124054): Make non-default and remove deprecated callback methods.
- @Deprecated
- public boolean hasFlag(int flagToCheckFor) {
- return (mFlags & flagToCheckFor) == flagToCheckFor;
- }
-
/**
* Checks if a specific property is set on this state
*/
@@ -438,6 +314,7 @@ public final class DeviceState {
* @see DeviceStateManager
* @hide
*/
+ @TestApi
public static final class Configuration implements Parcelable {
/** Unique identifier for the device state. */
@IntRange(from = MINIMUM_DEVICE_STATE_IDENTIFIER, to = MAXIMUM_DEVICE_STATE_IDENTIFIER)
@@ -563,29 +440,35 @@ public final class DeviceState {
};
/** @hide */
- public static class Builder {
+ @TestApi
+ public static final class Builder {
private final int mIdentifier;
+ @NonNull
private final String mName;
+ @NonNull
private Set<@SystemDeviceStateProperties Integer> mSystemProperties =
Collections.emptySet();
+ @NonNull
private Set<@PhysicalDeviceStateProperties Integer> mPhysicalProperties =
Collections.emptySet();
- public Builder(int identifier, String name) {
+ public Builder(int identifier, @NonNull String name) {
mIdentifier = identifier;
mName = name;
}
/** Sets the system properties for this {@link DeviceState.Configuration.Builder} */
+ @NonNull
public Builder setSystemProperties(
- Set<@SystemDeviceStateProperties Integer> systemProperties) {
+ @NonNull Set<@SystemDeviceStateProperties Integer> systemProperties) {
mSystemProperties = systemProperties;
return this;
}
/** Sets the system properties for this {@link DeviceState.Configuration.Builder} */
+ @NonNull
public Builder setPhysicalProperties(
- Set<@PhysicalDeviceStateProperties Integer> physicalProperties) {
+ @NonNull Set<@PhysicalDeviceStateProperties Integer> physicalProperties) {
mPhysicalProperties = physicalProperties;
return this;
}
@@ -594,6 +477,7 @@ public final class DeviceState {
* Returns a new {@link DeviceState.Configuration} whose values match the values set on
* the builder.
*/
+ @NonNull
public DeviceState.Configuration build() {
return new DeviceState.Configuration(mIdentifier, mName, mSystemProperties,
mPhysicalProperties);
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index a4c383343062..febc24c1465a 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -49,6 +49,7 @@ public final class DeviceStateManager {
*
* @hide
*/
+ @TestApi
public static final int INVALID_DEVICE_STATE_IDENTIFIER = -1;
/**
@@ -96,20 +97,6 @@ public final class DeviceStateManager {
/**
* Returns the list of device states that are supported and can be requested with
* {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
- * @deprecated use {@link #getSupportedDeviceStates()}
- * @hide
- */
- // TODO(b/325124054): Make non-default and remove deprecated callback methods.
- @TestApi
- @Deprecated
- @NonNull
- public int[] getSupportedStates() {
- return mGlobal.getSupportedStates();
- }
-
- /**
- * Returns the list of device states that are supported and can be requested with
- * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
*/
@NonNull
public List<DeviceState> getSupportedDeviceStates() {
@@ -239,23 +226,6 @@ public final class DeviceStateManager {
* Guaranteed to be called once on registration of the callback with the initial value and
* then on every subsequent change in the supported states.
*
- * @param supportedStates the new supported states.
- *
- * @see DeviceStateManager#getSupportedStates()
- * @deprecated use {@link #onSupportedStatesChanged(List)}
- * @hide
- */
- // TODO(b/325124054): Make non-default and remove deprecated callback methods.
- @TestApi
- @Deprecated
- default void onSupportedStatesChanged(@NonNull int[] supportedStates) {}
-
- /**
- * Called in response to a change in the states supported by the device.
- * <p>
- * Guaranteed to be called once on registration of the callback with the initial value and
- * then on every subsequent change in the supported states.
- *
* The supported device states may change due to certain states becoming unavailable
* due to device configuration or device conditions such as if the device is too hot or
* external monitors have been connected.
@@ -267,51 +237,14 @@ public final class DeviceStateManager {
default void onSupportedStatesChanged(@NonNull List<DeviceState> supportedStates) {}
/**
- * Called in response to a change in the base device state.
- * <p>
- * The base state is the state of the device without considering any requests made through
- * calls to {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}
- * from any client process. The base state is guaranteed to match the state provided with a
- * call to {@link #onStateChanged(int)} when there are no active requests from any process.
- * <p>
- * Guaranteed to be called once on registration of the callback with the initial value and
- * then on every subsequent change in the non-override state.
- *
- * @param state the new base device state.
- * @deprecated use {@link #onDeviceStateChanged(DeviceState)} and query for physical
- * properties that are relevant to your needs.
- * @hide
- */
- // TODO(b/325124054): Make non-default and remove deprecated callback methods.
- @TestApi
- @Deprecated
- default void onBaseStateChanged(int state) {}
-
- /**
* Called in response to device state changes.
* <p>
* Guaranteed to be called once on registration of the callback with the initial value and
* then on every subsequent change in device state.
*
* @param state the new device state.
- * @deprecated use {@link #onDeviceStateChanged(DeviceState)}
- * @hide
*/
- // TODO(b/325124054): Make non-default and remove deprecated callback methods.
- @TestApi
- @Deprecated
- void onStateChanged(int state);
-
- /**
- * Called in response to device state changes.
- * <p>
- * Guaranteed to be called once on registration of the callback with the initial value and
- * then on every subsequent change in device state.
- *
- * @param state the new device state.
- */
- // TODO(b/325124054): Make non-default and remove deprecated callback methods.
- default void onDeviceStateChanged(@NonNull DeviceState state) {}
+ void onDeviceStateChanged(@NonNull DeviceState state);
}
/**
@@ -340,9 +273,6 @@ public final class DeviceStateManager {
}
@Override
- public final void onStateChanged(int state) {}
-
- @Override
public final void onDeviceStateChanged(@NonNull DeviceState deviceState) {
final boolean folded;
if (mFeatureFlags.deviceStatePropertyApi()) {
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index d6cc00d45ec4..0c8401992913 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -90,33 +90,6 @@ public final class DeviceStateManagerGlobal {
}
/**
- * Returns the set of supported device states.
- *
- * @see DeviceStateManager#getSupportedStates()
- */
- // TODO(b/325124054): Remove unused methods when clients are migrated.
- public int[] getSupportedStates() {
- synchronized (mLock) {
- final DeviceStateInfo currentInfo;
- if (mLastReceivedInfo != null) {
- // If we have mLastReceivedInfo a callback is registered for this instance and it
- // is receiving the most recent info from the server. Use that info here.
- currentInfo = mLastReceivedInfo;
- } else {
- // If mLastReceivedInfo is null there is no registered callback so we manually
- // fetch the current info.
- try {
- currentInfo = mDeviceStateManager.getDeviceStateInfo();
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- return getSupportedStateIdentifiersLocked(currentInfo.supportedStates);
- }
- }
-
- /**
* Returns {@link List} of supported {@link DeviceState}s.
*
* @see DeviceStateManager#getSupportedDeviceStates()
@@ -264,14 +237,8 @@ public final class DeviceStateManagerGlobal {
mCallbacks.add(wrapper);
if (mLastReceivedInfo != null) {
- // Copy the array to prevent the callback from modifying the internal state.
- final int[] supportedStates = getSupportedStateIdentifiersLocked(
- mLastReceivedInfo.supportedStates);
- wrapper.notifySupportedStatesChanged(supportedStates);
wrapper.notifySupportedDeviceStatesChanged(
List.copyOf(mLastReceivedInfo.supportedStates));
- wrapper.notifyBaseStateChanged(mLastReceivedInfo.baseState.getIdentifier());
- wrapper.notifyStateChanged(mLastReceivedInfo.currentState.getIdentifier());
wrapper.notifyDeviceStateChanged(mLastReceivedInfo.currentState);
}
}
@@ -330,15 +297,6 @@ public final class DeviceStateManagerGlobal {
return -1;
}
- @GuardedBy("mLock")
- private int[] getSupportedStateIdentifiersLocked(List<DeviceState> states) {
- int[] identifiers = new int[states.size()];
- for (int i = 0; i < states.size(); i++) {
- identifiers[i] = states.get(i).getIdentifier();
- }
- return identifiers;
- }
-
@Nullable
private IBinder findRequestTokenLocked(@NonNull DeviceStateRequest request) {
for (int i = 0; i < mRequests.size(); i++) {
@@ -353,12 +311,10 @@ public final class DeviceStateManagerGlobal {
private void handleDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
ArrayList<DeviceStateCallbackWrapper> callbacks;
DeviceStateInfo oldInfo;
- int[] supportedStateIdentifiers;
synchronized (mLock) {
oldInfo = mLastReceivedInfo;
mLastReceivedInfo = info;
callbacks = new ArrayList<>(mCallbacks);
- supportedStateIdentifiers = getSupportedStateIdentifiersLocked(info.supportedStates);
}
final int diff = oldInfo == null ? ~0 : info.diff(oldInfo);
@@ -366,18 +322,11 @@ public final class DeviceStateManagerGlobal {
for (int i = 0; i < callbacks.size(); i++) {
callbacks.get(i).notifySupportedDeviceStatesChanged(
List.copyOf(info.supportedStates));
- callbacks.get(i).notifySupportedStatesChanged(supportedStateIdentifiers);
- }
- }
- if ((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0) {
- for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).notifyBaseStateChanged(info.baseState.getIdentifier());
}
}
if ((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0) {
for (int i = 0; i < callbacks.size(); i++) {
callbacks.get(i).notifyDeviceStateChanged(info.currentState);
- callbacks.get(i).notifyStateChanged(info.currentState.getIdentifier());
}
}
}
@@ -439,26 +388,11 @@ public final class DeviceStateManagerGlobal {
mExecutor = executor;
}
- void notifySupportedStatesChanged(int[] newSupportedStates) {
- mExecutor.execute(() ->
- mDeviceStateCallback.onSupportedStatesChanged(newSupportedStates));
- }
-
void notifySupportedDeviceStatesChanged(List<DeviceState> newSupportedDeviceStates) {
mExecutor.execute(() ->
mDeviceStateCallback.onSupportedStatesChanged(newSupportedDeviceStates));
}
- void notifyBaseStateChanged(int newBaseState) {
- execute("notifyBaseStateChanged",
- () -> mDeviceStateCallback.onBaseStateChanged(newBaseState));
- }
-
- void notifyStateChanged(int newDeviceState) {
- execute("notifyStateChanged",
- () -> mDeviceStateCallback.onStateChanged(newDeviceState));
- }
-
void notifyDeviceStateChanged(DeviceState newDeviceState) {
execute("notifyDeviceStateChanged",
() -> mDeviceStateCallback.onDeviceStateChanged(newDeviceState));
diff --git a/core/java/android/hardware/devicestate/DeviceStateRequest.java b/core/java/android/hardware/devicestate/DeviceStateRequest.java
index 893d765e48da..7665e2f173b9 100644
--- a/core/java/android/hardware/devicestate/DeviceStateRequest.java
+++ b/core/java/android/hardware/devicestate/DeviceStateRequest.java
@@ -115,8 +115,8 @@ public final class DeviceStateRequest {
* requested state.
* <p>
* Guaranteed to be called after a call to
- * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} with a state
- * matching the requested state.
+ * {@link DeviceStateManager.DeviceStateCallback#onDeviceStateChanged(DeviceState)} with a
+ * state matching the requested state.
*/
default void onRequestActivated(@NonNull DeviceStateRequest request) {}
@@ -124,7 +124,7 @@ public final class DeviceStateRequest {
* Called to indicate the request has been temporarily suspended.
* <p>
* Guaranteed to be called before a call to
- * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
+ * {@link DeviceStateManager.DeviceStateCallback#onDeviceStateChanged(DeviceState)}.
*/
default void onRequestSuspended(@NonNull DeviceStateRequest request) {}
@@ -134,7 +134,7 @@ public final class DeviceStateRequest {
* DeviceStateRequest.Callback)}.
* <p>
* Guaranteed to be called before a call to
- * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
+ * {@link DeviceStateManager.DeviceStateCallback#onDeviceStateChanged(DeviceState)}.
* <p>
* Note: A call to {@link #onRequestSuspended(DeviceStateRequest)} is not guaranteed to
* occur before this method.
diff --git a/core/java/android/hardware/devicestate/DeviceStateUtil.java b/core/java/android/hardware/devicestate/DeviceStateUtil.java
new file mode 100644
index 000000000000..627e740f4a5c
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateUtil.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.devicestate;
+
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
+
+import android.annotation.NonNull;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Utilities for {@link DeviceStateManager}.
+ * @hide
+ */
+public class DeviceStateUtil {
+ private DeviceStateUtil() { }
+
+ /**
+ * Returns the state identifier of the {@link DeviceState} that matches the
+ * {@code currentState}s physical properties. This will return the identifier of the
+ * {@link DeviceState} that matches the devices physical configuration.
+ *
+ * Returns {@link INVALID_DEVICE_STATE_IDENTIFIER} if there is no {@link DeviceState} in the
+ * provided list of {@code supportedStates} that matches.
+ * @hide
+ */
+ public static int calculateBaseStateIdentifier(@NonNull DeviceState currentState,
+ @NonNull List<DeviceState> supportedStates) {
+ DeviceState.Configuration stateConfiguration = currentState.getConfiguration();
+ for (int i = 0; i < supportedStates.size(); i++) {
+ DeviceState stateToCompare = supportedStates.get(i);
+ if (stateToCompare.getConfiguration().getPhysicalProperties().isEmpty()) {
+ continue;
+ }
+ if (isDeviceStateMatchingPhysicalProperties(stateConfiguration.getPhysicalProperties(),
+ supportedStates.get(i))) {
+ return supportedStates.get(i).getIdentifier();
+ }
+ }
+ return INVALID_DEVICE_STATE_IDENTIFIER;
+ }
+
+ /**
+ * Returns if the physical properties provided, matches the same physical properties on the
+ * provided {@link DeviceState}.
+ */
+ private static boolean isDeviceStateMatchingPhysicalProperties(
+ Set<@DeviceState.PhysicalDeviceStateProperties Integer> physicalProperties,
+ DeviceState state) {
+ Iterator<@DeviceState.PhysicalDeviceStateProperties Integer> iterator =
+ physicalProperties.iterator();
+ while (iterator.hasNext()) {
+ if (!state.hasProperty(iterator.next())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index eb26a768f2a6..4894fb1ec452 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1653,6 +1653,22 @@ public final class DisplayManager {
}
/**
+ * Allows internal application to restrict display modes to specified modeIds
+ *
+ * @param displayId display that restrictions will be applied to
+ * @param modeIds allowed mode ids
+ *
+ * @hide
+ */
+ @RequiresPermission("android.permission.RESTRICT_DISPLAY_MODES")
+ public void requestDisplayModes(int displayId, @Nullable int[] modeIds) {
+ if (modeIds != null && modeIds.length == 0) {
+ throw new IllegalArgumentException("requestDisplayModes: modesIds can't be empty");
+ }
+ mGlobal.requestDisplayModes(displayId, modeIds);
+ }
+
+ /**
* Listens for changes in available display devices.
*/
public interface DisplayListener {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 75f0ceb7e651..3d7b714a2f5b 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -38,6 +38,7 @@ import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.graphics.common.DisplayDecorationSupport;
import android.media.projection.IMediaProjection;
import android.media.projection.MediaProjection;
+import android.os.Binder;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
@@ -138,6 +139,8 @@ public final class DisplayManagerGlobal {
private int mWifiDisplayScanNestCount;
+ private final Binder mToken = new Binder();
+
@VisibleForTesting
public DisplayManagerGlobal(IDisplayManager dm) {
mDm = dm;
@@ -1182,6 +1185,20 @@ public final class DisplayManagerGlobal {
}
}
+ /**
+ * Sets allowed display mode ids
+ *
+ * @hide
+ */
+ @RequiresPermission("android.permission.RESTRICT_DISPLAY_MODES")
+ public void requestDisplayModes(int displayId, @Nullable int[] modeIds) {
+ try {
+ mDm.requestDisplayModes(mToken, displayId, modeIds);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
@Override
public void onDisplayEvent(int displayId, @DisplayEvent int event) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 83de4e45cf2f..70efc6f2e33f 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -235,4 +235,8 @@ interface IDisplayManager {
// Disable a connected display that is enabled.
@EnforcePermission("MANAGE_DISPLAYS")
void disableConnectedDisplay(int displayId);
+
+ // Restricts display modes to specified modeIds.
+ @EnforcePermission("RESTRICT_DISPLAY_MODES")
+ void requestDisplayModes(in IBinder token, int displayId, in @nullable int[] modeIds);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0869af5b1fd8..7e46818da745 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -8150,6 +8150,14 @@
<permission android:name="android.permission.EMERGENCY_INSTALL_PACKAGES"
android:protectionLevel="signature|privileged"/>
+ <!-- Allows internal applications to restrict display modes
+ <p>Not for use by third-party applications.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.RESTRICT_DISPLAY_MODES"
+ android:protectionLevel="signature" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 48ba52621f64..fc1fbb5368dc 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -120,6 +120,10 @@ public class ImeInsetsSourceConsumerTest {
final var statsToken = ImeTracker.Token.empty();
mImeConsumer.onWindowFocusGained(true);
mController.show(WindowInsets.Type.ime(), true /* fromIme */, statsToken);
+ // Called once through the show flow.
+ verify(mController).applyAnimation(
+ eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
+ eq(statsToken));
// set control and verify visibility is applied.
InsetsSourceControl control = new InsetsSourceControl(ID_IME,
@@ -127,11 +131,11 @@ public class ImeInsetsSourceConsumerTest {
mController.onControlsChanged(new InsetsSourceControl[] { control });
// IME show animation should be triggered when control becomes available.
verify(mController).applyAnimation(
- eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
- eq(statsToken));
+ eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
+ and(not(eq(statsToken)), notNull()));
verify(mController, never()).applyAnimation(
- eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(true) /* fromIme */,
- eq(statsToken));
+ eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
+ and(not(eq(statsToken)), notNull()));
});
}
@@ -159,6 +163,10 @@ public class ImeInsetsSourceConsumerTest {
final var statsToken = ImeTracker.Token.empty();
if (imeVisible) {
mController.show(WindowInsets.Type.ime(), true /* fromIme */, statsToken);
+ // Called once through the show flow.
+ verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
+ eq(true) /* show */, eq(true) /* fromIme */,
+ eq(false) /* skipAnim */, eq(statsToken));
}
// set control and verify visibility is applied.
@@ -184,13 +192,17 @@ public class ImeInsetsSourceConsumerTest {
if (!hasViewFocus) {
final var statsTokenNext = ImeTracker.Token.empty();
mController.show(WindowInsets.Type.ime(), true /* fromIme */, statsTokenNext);
+ // Called once through the show flow.
+ verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
+ eq(true) /* show */, eq(true) /* fromIme */,
+ eq(false) /* skipAnim */, eq(statsTokenNext));
mController.onControlsChanged(new InsetsSourceControl[]{ control });
// Verify IME show animation should be triggered when control becomes available and
// the animation will be skipped by getAndClearSkipAnimationOnce invoked.
verify(control).getAndClearSkipAnimationOnce();
verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
- eq(true) /* show */, eq(true) /* fromIme */,
- eq(false) /* skipAnim */, eq(statsTokenNext));
+ eq(true) /* show */, eq(false) /* fromIme */,
+ eq(true) /* skipAnim */, and(not(eq(statsToken)), notNull()));
}
});
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
index fa35b632a6b3..98935e95deaf 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
@@ -19,13 +19,14 @@ package androidx.window.common;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN;
-import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE;
import static androidx.window.common.CommonFoldingFeature.parseListFromString;
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
+import android.hardware.devicestate.DeviceStateUtil;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
@@ -54,29 +55,27 @@ public final class DeviceStateManagerFoldingFeatureProducer
private static final boolean DEBUG = false;
/**
- * Emulated device state {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} to
+ * Emulated device state
+ * {@link DeviceStateManager.DeviceStateCallback#onDeviceStateChanged(DeviceState)} to
* {@link CommonFoldingFeature.State} map.
*/
private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
/**
- * Emulated device state received via
- * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
- * "Emulated" states differ from "base" state in the sense that they may not correspond 1:1 with
- * physical device states. They represent the state of the device when various software
- * features and APIs are applied. The emulated states generally consist of all "base" states,
- * but may have additional states such as "concurrent" or "rear display". Concurrent mode for
- * example is activated via public API and can be active in both the "open" and "half folded"
- * device states.
+ * Device state received via
+ * {@link DeviceStateManager.DeviceStateCallback#onDeviceStateChanged(DeviceState)}.
+ * The identifier returned through {@link DeviceState#getIdentifier()} may not correspond 1:1
+ * with the physical state of the device. This could correspond to the system state of the
+ * device when various software features or overrides are applied. The emulated states generally
+ * consist of all "base" states, but may have additional states such as "concurrent" or
+ * "rear display". Concurrent mode for example is activated via public API and can be active in
+ * both the "open" and "half folded" device states.
*/
- private int mCurrentDeviceState = INVALID_DEVICE_STATE_IDENTIFIER;
+ private DeviceState mCurrentDeviceState = new DeviceState(
+ new DeviceState.Configuration.Builder(INVALID_DEVICE_STATE_IDENTIFIER,
+ "INVALID").build());
- /**
- * Base device state received via
- * {@link DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)}.
- * "Base" in this context means the "physical" state of the device.
- */
- private int mCurrentBaseDeviceState = INVALID_DEVICE_STATE_IDENTIFIER;
+ private List<DeviceState> mSupportedStates;
@NonNull
private final RawFoldingFeatureProducer mRawFoldSupplier;
@@ -85,22 +84,11 @@ public final class DeviceStateManagerFoldingFeatureProducer
private final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() {
@Override
- public void onStateChanged(int state) {
+ public void onDeviceStateChanged(@NonNull DeviceState state) {
mCurrentDeviceState = state;
mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer
.this::notifyFoldingFeatureChange);
}
-
- @Override
- public void onBaseStateChanged(int state) {
- mCurrentBaseDeviceState = state;
-
- if (mDeviceStateToPostureMap.get(mCurrentDeviceState)
- == COMMON_STATE_USE_BASE_STATE) {
- mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer
- .this::notifyFoldingFeatureChange);
- }
- }
};
public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context,
@@ -109,6 +97,7 @@ public final class DeviceStateManagerFoldingFeatureProducer
mRawFoldSupplier = rawFoldSupplier;
String[] deviceStatePosturePairs = context.getResources()
.getStringArray(R.array.config_device_state_postures);
+ mSupportedStates = deviceStateManager.getSupportedDeviceStates();
boolean isHalfOpenedSupported = false;
for (String deviceStatePosturePair : deviceStatePosturePairs) {
String[] deviceStatePostureMapping = deviceStatePosturePair.split(":");
@@ -168,7 +157,7 @@ public final class DeviceStateManagerFoldingFeatureProducer
*/
private boolean isCurrentStateValid() {
// If the device state is not found in the map, indexOfKey returns a negative number.
- return mDeviceStateToPostureMap.indexOfKey(mCurrentDeviceState) >= 0;
+ return mDeviceStateToPostureMap.indexOfKey(mCurrentDeviceState.getIdentifier()) >= 0;
}
@Override
@@ -177,7 +166,9 @@ public final class DeviceStateManagerFoldingFeatureProducer
if (hasListeners()) {
mRawFoldSupplier.addDataChangedCallback(this::notifyFoldingFeatureChange);
} else {
- mCurrentDeviceState = INVALID_DEVICE_STATE_IDENTIFIER;
+ mCurrentDeviceState = new DeviceState(
+ new DeviceState.Configuration.Builder(INVALID_DEVICE_STATE_IDENTIFIER,
+ "INVALID").build());
mRawFoldSupplier.removeDataChangedCallback(this::notifyFoldingFeatureChange);
}
}
@@ -251,10 +242,13 @@ public final class DeviceStateManagerFoldingFeatureProducer
@CommonFoldingFeature.State
private int currentHingeState() {
@CommonFoldingFeature.State
- int posture = mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN);
+ int posture = mDeviceStateToPostureMap.get(mCurrentDeviceState.getIdentifier(),
+ COMMON_STATE_UNKNOWN);
if (posture == CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE) {
- posture = mDeviceStateToPostureMap.get(mCurrentBaseDeviceState, COMMON_STATE_UNKNOWN);
+ posture = mDeviceStateToPostureMap.get(
+ DeviceStateUtil.calculateBaseStateIdentifier(mCurrentDeviceState,
+ mSupportedStates), COMMON_STATE_UNKNOWN);
}
return posture;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
index d31bf2a662a3..a3d2d7f4dcdf 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -20,6 +20,7 @@ import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STA
import android.app.Activity;
import android.content.Context;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateRequest;
import android.hardware.display.DisplayManager;
@@ -40,6 +41,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -101,7 +103,9 @@ public class WindowAreaComponentImpl implements WindowAreaComponent,
mDisplayManager = context.getSystemService(DisplayManager.class);
mExecutor = context.getMainExecutor();
- mCurrentSupportedDeviceStates = mDeviceStateManager.getSupportedStates();
+ // TODO(b/329436166): Update the usage of device state manager API's
+ mCurrentSupportedDeviceStates = getSupportedStateIdentifiers(
+ mDeviceStateManager.getSupportedDeviceStates());
mFoldedDeviceStates = context.getResources().getIntArray(
R.array.config_foldedDeviceStates);
@@ -446,9 +450,10 @@ public class WindowAreaComponentImpl implements WindowAreaComponent,
}
@Override
- public void onSupportedStatesChanged(int[] supportedStates) {
+ public void onSupportedStatesChanged(@NonNull List<DeviceState> supportedStates) {
synchronized (mLock) {
- mCurrentSupportedDeviceStates = supportedStates;
+ // TODO(b/329436166): Update the usage of device state manager API's
+ mCurrentSupportedDeviceStates = getSupportedStateIdentifiers(supportedStates);
updateRearDisplayStatusListeners(getCurrentRearDisplayModeStatus());
updateRearDisplayPresentationStatusListeners(
getCurrentRearDisplayPresentationModeStatus());
@@ -456,9 +461,10 @@ public class WindowAreaComponentImpl implements WindowAreaComponent,
}
@Override
- public void onStateChanged(int state) {
+ public void onDeviceStateChanged(@NonNull DeviceState state) {
synchronized (mLock) {
- mCurrentDeviceState = state;
+ // TODO(b/329436166): Update the usage of device state manager API's
+ mCurrentDeviceState = state.getIdentifier();
updateRearDisplayStatusListeners(getCurrentRearDisplayModeStatus());
updateRearDisplayPresentationStatusListeners(
getCurrentRearDisplayPresentationModeStatus());
@@ -482,6 +488,15 @@ public class WindowAreaComponentImpl implements WindowAreaComponent,
return WindowAreaComponent.STATUS_AVAILABLE;
}
+ // TODO(b/329436166): Remove and update the usage of device state manager API's
+ private int[] getSupportedStateIdentifiers(@NonNull List<DeviceState> states) {
+ int[] identifiers = new int[states.size()];
+ for (int i = 0; i < states.size(); i++) {
+ identifiers[i] = states.get(i).getIdentifier();
+ }
+ return identifiers;
+ }
+
/**
* Helper method to determine if a rear display session is currently active by checking
* if the current device state is that which corresponds to {@code mRearDisplayState}.
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 7dd39613b438..00fb298ea1cc 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -272,6 +272,10 @@
<dimen name="bubble_bar_expanded_view_corner_radius">16dp</dimen>
<!-- Corner radius for expanded view while it is being dragged -->
<dimen name="bubble_bar_expanded_view_corner_radius_dragged">28dp</dimen>
+ <!-- Width of the box around bottom center of the screen where drag only leads to dismiss -->
+ <dimen name="bubble_bar_dismiss_zone_width">192dp</dimen>
+ <!-- Height of the box around bottom center of the screen where drag only leads to dismiss -->
+ <dimen name="bubble_bar_dismiss_zone_height">242dp</dimen>
<!-- Bottom and end margin for compat buttons. -->
<dimen name="compat_button_margin">24dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
index 056598b86d58..b5b8a81c8886 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
@@ -17,8 +17,10 @@
package com.android.wm.shell.bubbles.bar
import android.annotation.SuppressLint
+import android.graphics.RectF
import android.view.MotionEvent
import android.view.View
+import com.android.wm.shell.R
import com.android.wm.shell.bubbles.BubblePositioner
import com.android.wm.shell.common.bubbles.BubbleBarLocation
import com.android.wm.shell.common.bubbles.DismissView
@@ -43,6 +45,8 @@ class BubbleBarExpandedViewDragController(
private val magnetizedExpandedView: MagnetizedObject<BubbleBarExpandedView> =
MagnetizedObject.magnetizeView(expandedView)
private val magnetizedDismissTarget: MagnetizedObject.MagneticTarget
+ private val dismissZoneHeight: Int
+ private val dismissZoneWidth: Int
init {
magnetizedExpandedView.magnetListener = MagnetListener()
@@ -74,6 +78,11 @@ class BubbleBarExpandedViewDragController(
}
return@setOnTouchListener dragMotionEventHandler.onTouch(view, event) || magnetConsumed
}
+
+ dismissZoneHeight =
+ dismissView.resources.getDimensionPixelSize(R.dimen.bubble_bar_dismiss_zone_height)
+ dismissZoneWidth =
+ dismissView.resources.getDimensionPixelSize(R.dimen.bubble_bar_dismiss_zone_width)
}
/** Listener to receive callback about dragging events */
@@ -97,12 +106,23 @@ class BubbleBarExpandedViewDragController(
private var isMoving = false
private var screenCenterX: Int = -1
private var isOnLeft = false
+ private val dismissZone = RectF()
override fun onDown(v: View, ev: MotionEvent): Boolean {
// While animating, don't allow new touch events
if (expandedView.isAnimating) return false
- screenCenterX = bubblePositioner.screenRect.centerX()
isOnLeft = bubblePositioner.isBubbleBarOnLeft
+
+ val screenRect = bubblePositioner.screenRect
+ screenCenterX = screenRect.centerX()
+ val screenBottom = screenRect.bottom
+
+ dismissZone.set(
+ screenCenterX - dismissZoneWidth / 2f,
+ (screenBottom - dismissZoneHeight).toFloat(),
+ screenCenterX + dismissZoneHeight / 2f,
+ screenBottom.toFloat()
+ )
return true
}
@@ -122,6 +142,11 @@ class BubbleBarExpandedViewDragController(
expandedView.translationY = expandedViewInitialTranslationY + dy
dismissView.show()
+ // Check if we are in the zone around dismiss view where drag can only lead to dismiss
+ if (dismissZone.contains(ev.rawX, ev.rawY)) {
+ return
+ }
+
if (isOnLeft && ev.rawX > screenCenterX) {
isOnLeft = false
dragListener.onLocationChanged(BubbleBarLocation.RIGHT)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java
index 8b4ac1a8dc79..d17e8620ff12 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java
@@ -107,7 +107,7 @@ public class DevicePostureController {
DeviceStateManager.class);
if (deviceStateManager != null) {
deviceStateManager.registerCallback(mMainExecutor, state -> onDevicePostureChanged(
- mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN)));
+ mDeviceStateToPostureMap.get(state.getIdentifier(), DEVICE_POSTURE_UNKNOWN)));
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 3266c12f3ad2..b151a538670d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -60,10 +60,12 @@ import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
@@ -161,6 +163,11 @@ final class SettingsState {
private static final String APEX_DIR = "/apex";
private static final String APEX_ACONFIG_PATH_SUFFIX = "/etc/aconfig_flags.pb";
+ private static final String STORAGE_MIGRATION_FLAG =
+ "core_experiments_team_internal/com.android.providers.settings.storage_test_mission_1";
+ private static final String STORAGE_MIGRATION_LOG =
+ "/metadata/aconfig/flags/storage_migration.log";
+
/**
* This tag is applied to all aconfig default value-loaded flags.
*/
@@ -1439,6 +1446,20 @@ final class SettingsState {
}
}
+ if (name != null && name.equals(STORAGE_MIGRATION_FLAG) && value.equals("true")) {
+ File file = new File(STORAGE_MIGRATION_LOG);
+ if (!file.exists()) {
+ try (BufferedWriter writer =
+ new BufferedWriter(new FileWriter(STORAGE_MIGRATION_LOG))) {
+ final long timestamp = System.currentTimeMillis();
+ String entry = String.format("%d | Log init", timestamp);
+ writer.write(entry);
+ } catch (IOException e) {
+ Slog.e(LOG_TAG, "failed to write storage migration file", e);
+ }
+ }
+ }
+
mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag,
fromSystem, id, isPreservedInRestore));
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
index 2e14e9b8be4c..c572bdb57c6a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
+++ b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
@@ -33,3 +33,10 @@ flag {
bug: "327383546"
is_fixed_read_only: true
}
+
+flag {
+ name: "storage_test_mission_1"
+ namespace: "core_experiments_team_internal"
+ description: "If this flag is detected as true on boot, writes a logfile to track storage migration correctness."
+ bug: "328444881"
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 3c18f17b8e96..f12320163bc6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -434,7 +434,7 @@
</intent-filter>
</receiver>
- <activity android:name=".screenshot.LongScreenshotActivity"
+ <activity android:name=".screenshot.scroll.LongScreenshotActivity"
android:theme="@style/LongScreenshotActivity"
android:process=":screenshot"
android:exported="false"
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 63ec54fbef9c..82083f99ba3e 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
@@ -605,6 +605,8 @@ private class SwipeTransition(
override val isInitiatedByUserInput = true
+ override var bouncingScene: SceneKey? = null
+
/** The current offset caused by the drag gesture. */
var dragOffset by mutableFloatStateOf(0f)
@@ -694,14 +696,31 @@ private class SwipeTransition(
): OffsetAnimation {
return startOffsetAnimation {
val animatable = Animatable(dragOffset, OffsetVisibilityThreshold)
+ val isTargetGreater = targetOffset > animatable.value
val job =
coroutineScope
.launch {
- animatable.animateTo(
- targetValue = targetOffset,
- animationSpec = swipeSpec,
- initialVelocity = initialVelocity,
- )
+ try {
+ animatable.animateTo(
+ targetValue = targetOffset,
+ animationSpec = swipeSpec,
+ initialVelocity = initialVelocity,
+ ) {
+ if (bouncingScene == null) {
+ val isBouncing =
+ if (isTargetGreater) {
+ value > targetOffset
+ } else {
+ value < targetOffset
+ }
+ if (isBouncing) {
+ bouncingScene = targetScene
+ }
+ }
+ }
+ } finally {
+ bouncingScene = null
+ }
}
// Make sure that we settle to target scene at the end of the animation or if
// the animation is cancelled.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index c7186da6b961..f1177a8eb864 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -588,7 +588,8 @@ private inline fun <T> computeValue(
// TODO(b/290184746): Make sure that we don't overflow transformations associated to a
// range.
val directionSign = if (transition.isUpOrLeft) -1 else 1
- val overscrollProgress = transition.progress.let { if (it > 1f) it - 1f else it }
+ val isToScene = overscroll.scene == transition.toScene
+ val overscrollProgress = transition.progress.let { if (isToScene) it - 1f else it }
val progress = directionSign * overscrollProgress
val rangeProgress = propertySpec.range?.progress(progress) ?: progress
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index e6f5d585e915..617a8ea0b6cd 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -255,6 +255,12 @@ sealed interface TransitionState {
*/
val overscrollScope: OverscrollScope
+ /**
+ * The scene around which the transition is currently bouncing. When not `null`, this
+ * transition is currently oscillating around this scene and will soon settle to that scene.
+ */
+ val bouncingScene: SceneKey?
+
companion object {
const val DistanceUnspecified = 0f
}
@@ -287,9 +293,10 @@ internal abstract class BaseSceneTransitionLayoutState(
val transition = currentTransition ?: return null
if (transition !is TransitionState.HasOverscrollProperties) return null
val progress = transition.progress
+ val bouncingScene = transition.bouncingScene
return when {
- progress < 0f -> fromOverscrollSpec
- progress > 1f -> toOverscrollSpec
+ progress < 0f || bouncingScene == transition.fromScene -> fromOverscrollSpec
+ progress > 1f || bouncingScene == transition.toScene -> toOverscrollSpec
else -> null
}
}
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 26e01fefcb9b..080476101821 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
@@ -16,6 +16,8 @@
package com.android.compose.animation.scene
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.Orientation
@@ -752,4 +754,55 @@ class ElementTest {
assertThat(state.currentOverscrollSpec).isNotNull()
fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 1.5f)
}
+
+ @Test
+ fun elementTransitionWithDistanceDuringOverscrollBouncing() {
+ val layoutWidth = 200.dp
+ val layoutHeight = 400.dp
+ val state =
+ setupOverscrollScenario(
+ layoutWidth = layoutWidth,
+ layoutHeight = layoutHeight,
+ sceneTransitions = {
+ defaultSwipeSpec =
+ spring(
+ dampingRatio = Spring.DampingRatioMediumBouncy,
+ stiffness = Spring.StiffnessLow,
+ )
+
+ overscroll(TestScenes.SceneB, Orientation.Vertical) {
+ // On overscroll 100% -> Foo should translate by layoutHeight
+ translate(TestElements.Foo, y = { absoluteDistance })
+ }
+ },
+ firstScroll = 1f, // 100% scroll
+ )
+
+ val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
+ fooElement.assertTopPositionInRootIsEqualTo(0.dp)
+
+ rule.onRoot().performTouchInput {
+ // Scroll another 50%
+ moveBy(Offset(0f, layoutHeight.toPx() * 0.5f), delayMillis = 1_000)
+ }
+
+ val transition = state.currentTransition
+ assertThat(transition).isNotNull()
+ transition as TransitionState.HasOverscrollProperties
+
+ // Scroll 150% (100% scroll + 50% overscroll)
+ assertThat(transition.progress).isEqualTo(1.5f)
+ assertThat(state.currentOverscrollSpec).isNotNull()
+ fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * (transition.progress - 1f))
+
+ // finger raised
+ rule.onRoot().performTouchInput { up() }
+
+ // The target value is 1f, but the spring (defaultSwipeSpec) allows you to go to a lower
+ // value.
+ rule.waitUntil(timeoutMillis = 10_000) { transition.progress < 1f }
+
+ assertThat(state.currentOverscrollSpec).isNotNull()
+ assertThat(transition.bouncingScene).isEqualTo(transition.toScene)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt
index 73a66c629024..a32fe2273804 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt
@@ -27,6 +27,7 @@ fun transition(
isInitiatedByUserInput: Boolean = false,
isUserInputOngoing: Boolean = false,
isUpOrLeft: Boolean = false,
+ bouncingScene: SceneKey? = null,
orientation: Orientation = Orientation.Horizontal,
): TransitionState.Transition {
return object : TransitionState.Transition(from, to), TransitionState.HasOverscrollProperties {
@@ -37,6 +38,7 @@ fun transition(
override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput
override val isUserInputOngoing: Boolean = isUserInputOngoing
override val isUpOrLeft: Boolean = isUpOrLeft
+ override val bouncingScene: SceneKey? = bouncingScene
override val orientation: Orientation = orientation
override val overscrollScope: OverscrollScope =
object : OverscrollScope {
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml
index b562d7b5ee48..6780e5721af3 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml
@@ -85,6 +85,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
+ android:focusable="false"
androidprv:layout_constraintVertical_bias="1.0"
androidprv:layout_constraintDimensionRatio="1.0"
androidprv:layout_constraintStart_toStartOf="parent"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index d9011c26dfd7..d991581c2665 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -57,6 +57,7 @@
android:id="@+id/lockPatternView"
android:layout_width="0dp"
android:layout_height="0dp"
+ android:focusable="false"
androidprv:layout_constraintTop_toBottomOf="@id/pattern_top_guideline"
androidprv:layout_constraintBottom_toBottomOf="parent"
androidprv:layout_constraintLeft_toLeftOf="parent"
diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
index 5fe74aa6817f..2d63c8da54f9 100644
--- a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
@@ -26,7 +26,7 @@ android:layout_height="match_parent">
android:paddingHorizontal="16dp"
android:paddingVertical="16dp"
android:visibility="visible"
- app:layout_constraintBottom_toTopOf="@+id/bottomGuideline"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/rightGuideline"
app:layout_constraintStart_toStartOf="@+id/leftGuideline"
app:layout_constraintTop_toTopOf="@+id/topGuideline" />
@@ -59,7 +59,7 @@ android:layout_height="match_parent">
android:layout_width="0dp"
android:layout_height="0dp"
android:fillViewport="true"
- android:padding="16dp"
+ android:padding="24dp"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@+id/buttonBarrier"
@@ -82,20 +82,20 @@ android:layout_height="match_parent">
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <LinearLayout
- android:id="@+id/customized_view_container"
- android:layout_width="wrap_content"
+ <TextView
+ android:id="@+id/logo_description"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:paddingHorizontal="0dp"
- android:visibility="gone"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:ellipsize="marquee"
+ android:gravity="@integer/biometric_dialog_text_gravity"
+ android:marqueeRepeatLimit="1"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:paddingLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/logo"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.0"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/subtitle"
- app:layout_constraintVertical_bias="0.0" />
+ app:layout_constraintStart_toEndOf="@+id/logo"
+ app:layout_constraintTop_toTopOf="@+id/logo" />
<Space
android:id="@+id/space_above_content"
@@ -108,6 +108,7 @@ android:layout_height="match_parent">
style="@style/TextAppearance.AuthCredential.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
android:gravity="@integer/biometric_dialog_text_gravity"
android:paddingHorizontal="0dp"
android:textAlignment="viewStart"
@@ -124,6 +125,7 @@ android:layout_height="match_parent">
style="@style/TextAppearance.AuthCredential.Subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
android:gravity="@integer/biometric_dialog_text_gravity"
android:paddingHorizontal="0dp"
android:textAlignment="viewStart"
@@ -133,14 +135,14 @@ android:layout_height="match_parent">
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
- <TextView
- android:id="@+id/description"
- style="@style/TextAppearance.AuthCredential.Description"
+ <LinearLayout
+ android:id="@+id/customized_view_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
android:paddingHorizontal="0dp"
- android:textAlignment="viewStart"
+ android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
@@ -149,19 +151,20 @@ android:layout_height="match_parent">
app:layout_constraintVertical_bias="0.0" />
<TextView
- android:id="@+id/logo_description"
- android:layout_width="0dp"
+ android:id="@+id/description"
+ style="@style/TextAppearance.AuthCredential.Description"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:ellipsize="marquee"
android:gravity="@integer/biometric_dialog_text_gravity"
- android:marqueeRepeatLimit="1"
- android:singleLine="true"
+ android:paddingHorizontal="0dp"
android:textAlignment="viewStart"
- android:paddingLeft="8dp"
- app:layout_constraintBottom_toBottomOf="@+id/logo"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@+id/logo"
- app:layout_constraintTop_toTopOf="@+id/logo" />
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/subtitle"
+ app:layout_constraintVertical_bias="0.0" />
+
<androidx.constraintlayout.widget.Barrier
android:id="@+id/contentBarrier"
@@ -178,7 +181,7 @@ android:layout_height="match_parent">
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
+ android:layout_marginTop="24dp"
android:accessibilityLiveRegion="polite"
android:fadingEdge="horizontal"
android:gravity="center_horizontal"
@@ -192,80 +195,15 @@ android:layout_height="match_parent">
app:layout_constraintTop_toBottomOf="@+id/biometric_icon"
app:layout_constraintVertical_bias="0.0" />
- <!-- Negative Button, reserved for app -->
- <Button
- android:id="@+id/button_negative"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
- app:layout_constraintStart_toStartOf="@+id/scrollView" />
-
- <!-- Cancel Button, replaces negative button when biometric is accepted -->
- <Button
- android:id="@+id/button_cancel"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:text="@string/cancel"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
- app:layout_constraintStart_toStartOf="@+id/scrollView" />
-
- <!-- "Use Credential" Button, replaces if device credential is allowed -->
- <Button
- android:id="@+id/button_use_credential"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
- app:layout_constraintStart_toStartOf="@+id/scrollView" />
-
- <!-- Positive Button -->
- <Button
- android:id="@+id/button_confirm"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginRight="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/biometric_dialog_confirm"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
- app:layout_constraintEnd_toEndOf="@+id/scrollView"
- tools:visibility="invisible" />
-
- <!-- Try Again Button -->
- <Button
- android:id="@+id/button_try_again"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginRight="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/biometric_dialog_try_again"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
- app:layout_constraintEnd_toEndOf="@+id/scrollView" />
+ <include
+ android:id="@+id/button_bar"
+ layout="@layout/biometric_prompt_button_bar"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintBottom_toTopOf="@id/bottomGuideline"
+ app:layout_constraintEnd_toEndOf="@id/scrollView"
+ app:layout_constraintStart_toStartOf="@id/scrollView"
+ app:layout_constraintTop_toBottomOf="@id/scrollView" />
<!-- Guidelines for setting panel border -->
<androidx.constraintlayout.widget.Barrier
@@ -282,7 +220,7 @@ android:layout_height="match_parent">
android:layout_height="wrap_content"
app:barrierAllowsGoneWidgets="false"
app:barrierDirection="top"
- app:constraint_referenced_ids="button_negative, button_cancel, button_use_credential, button_confirm, button_try_again" />
+ app:constraint_referenced_ids="button_bar" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/leftGuideline"
diff --git a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
index 5b30dfb77342..329fc466d378 100644
--- a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
@@ -23,92 +23,29 @@
android:clickable="true"
android:clipToOutline="true"
android:importantForAccessibility="no"
- android:paddingHorizontal="16dp"
- android:paddingVertical="16dp"
android:visibility="visible"
- app:layout_constraintBottom_toTopOf="@+id/bottomGuideline"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/rightGuideline"
app:layout_constraintStart_toStartOf="@+id/leftGuideline"
app:layout_constraintTop_toTopOf="@+id/topBarrier" />
- <Button
- android:id="@+id/button_negative"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintStart_toStartOf="@+id/panel" />
-
- <Button
- android:id="@+id/button_cancel"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:text="@string/cancel"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintStart_toStartOf="@+id/panel" />
-
- <Button
- android:id="@+id/button_use_credential"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintStart_toStartOf="@+id/panel" />
-
- <Button
- android:id="@+id/button_confirm"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginRight="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/biometric_dialog_confirm"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintEnd_toEndOf="@+id/panel"
- tools:visibility="invisible" />
-
- <Button
- android:id="@+id/button_try_again"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginRight="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/biometric_dialog_try_again"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintEnd_toEndOf="@+id/panel" />
-
- <!-- Negative Button, reserved for app -->
+ <include
+ layout="@layout/biometric_prompt_button_bar"
+ android:id="@+id/button_bar"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ app:layout_constraintBottom_toTopOf="@id/bottomGuideline"
+ app:layout_constraintEnd_toEndOf="@id/panel"
+ app:layout_constraintStart_toStartOf="@id/panel"/>
<ScrollView
android:id="@+id/scrollView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fillViewport="true"
- android:padding="16dp"
+ android:paddingBottom="36dp"
+ android:paddingHorizontal="24dp"
+ android:paddingTop="24dp"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@+id/biometric_icon"
@@ -134,18 +71,19 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <LinearLayout
- android:id="@+id/customized_view_container"
- android:layout_width="wrap_content"
+ <TextView
+ android:id="@+id/logo_description"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:paddingHorizontal="@dimen/biometric_prompt_content_container_padding_horizontal"
- android:visibility="gone"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:ellipsize="marquee"
+ android:gravity="@integer/biometric_dialog_text_gravity"
+ android:marqueeRepeatLimit="1"
+ android:singleLine="true"
+ android:paddingTop="16dp"
+ app:layout_constraintBottom_toTopOf="@+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/subtitle" />
+ app:layout_constraintTop_toBottomOf="@+id/logo" />
<Space
android:id="@+id/space_above_content"
@@ -159,6 +97,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="@integer/biometric_dialog_text_gravity"
+ android:paddingTop="16dp"
app:layout_constraintBottom_toTopOf="@+id/subtitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -170,23 +109,24 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="@integer/biometric_dialog_text_gravity"
+ android:paddingTop="16dp"
app:layout_constraintBottom_toTopOf="@+id/contentBarrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
- <TextView
- android:id="@+id/logo_description"
- android:layout_width="match_parent"
+ <LinearLayout
+ android:id="@+id/customized_view_container"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:marqueeRepeatLimit="1"
- android:singleLine="true"
- app:layout_constraintBottom_toTopOf="@+id/title"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:paddingHorizontal="@dimen/biometric_prompt_content_container_padding_horizontal"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/logo" />
+ app:layout_constraintTop_toBottomOf="@+id/subtitle" />
<TextView
android:id="@+id/description"
@@ -215,7 +155,7 @@
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
+ android:layout_marginTop="24dp"
android:accessibilityLiveRegion="polite"
android:fadingEdge="horizontal"
android:gravity="center_horizontal"
@@ -247,7 +187,7 @@
android:layout_height="wrap_content"
app:barrierAllowsGoneWidgets="false"
app:barrierDirection="top"
- app:constraint_referenced_ids="button_negative, button_cancel, button_use_credential, button_confirm, button_try_again" />
+ app:constraint_referenced_ids="button_bar" />
<!-- Guidelines for setting panel border -->
<androidx.constraintlayout.widget.Guideline
diff --git a/packages/SystemUI/res/layout/app_clips_screenshot.xml b/packages/SystemUI/res/layout/app_clips_screenshot.xml
index cb638ee87834..bcc7bca8c915 100644
--- a/packages/SystemUI/res/layout/app_clips_screenshot.xml
+++ b/packages/SystemUI/res/layout/app_clips_screenshot.xml
@@ -69,7 +69,7 @@
tools:minHeight="100dp"
tools:minWidth="100dp" />
- <com.android.systemui.screenshot.CropView
+ <com.android.systemui.screenshot.scroll.CropView
android:id="@+id/crop_view"
android:layout_width="0px"
android:layout_height="0px"
diff --git a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
new file mode 100644
index 000000000000..810c7433e4ad
--- /dev/null
+++ b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <!-- Negative Button, reserved for app -->
+ <Button
+ android:id="@+id/button_negative"
+ style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="24dp"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <!-- Cancel Button, replaces negative button when biometric is accepted -->
+ <Button
+ android:id="@+id/button_cancel"
+ style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="24dp"
+ android:text="@string/cancel"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <!-- "Use Credential" Button, replaces if device credential is allowed -->
+ <Button
+ android:id="@+id/button_use_credential"
+ style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="24dp"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <!-- Positive Button -->
+ <Button
+ android:id="@+id/button_confirm"
+ style="@*android:style/Widget.DeviceDefault.Button.Colored"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="24dp"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:text="@string/biometric_dialog_confirm"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+ <!-- Try Again Button -->
+ <Button
+ android:id="@+id/button_try_again"
+ style="@*android:style/Widget.DeviceDefault.Button.Colored"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="24dp"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:text="@string/biometric_dialog_try_again"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
index 74292b4edf0a..6391813754d0 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
@@ -23,43 +23,29 @@
android:clickable="true"
android:clipToOutline="true"
android:importantForAccessibility="no"
- android:paddingHorizontal="16dp"
- android:paddingVertical="16dp"
android:visibility="visible"
- app:layout_constraintBottom_toTopOf="@+id/bottomGuideline"
- app:layout_constraintEnd_toStartOf="@+id/rightGuideline"
- app:layout_constraintStart_toStartOf="@+id/leftGuideline"
- app:layout_constraintTop_toTopOf="@+id/topBarrier" />
-
- <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
- android:id="@+id/biometric_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.8"
- tools:srcCompat="@tools:sample/avatars" />
+ app:layout_constraintEnd_toEndOf="@id/rightGuideline"
+ app:layout_constraintStart_toStartOf="@id/leftGuideline"
+ app:layout_constraintTop_toTopOf="@id/topBarrier" />
- <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
- android:id="@+id/biometric_icon_overlay"
+ <include
+ android:id="@+id/button_bar"
+ layout="@layout/biometric_prompt_button_bar"
android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_gravity="center"
- android:contentDescription="@null"
- android:scaleType="fitXY"
- app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
- app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
- app:layout_constraintStart_toStartOf="@+id/biometric_icon"
- app:layout_constraintTop_toTopOf="@+id/biometric_icon" />
+ android:layout_height="match_parent"
+ app:layout_constraintBottom_toTopOf="@id/bottomGuideline"
+ app:layout_constraintEnd_toEndOf="@id/panel"
+ app:layout_constraintStart_toStartOf="@id/panel" />
<ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
- android:padding="16dp"
+ android:paddingBottom="36dp"
+ android:paddingHorizontal="24dp"
+ android:paddingTop="24dp"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@+id/biometric_icon"
@@ -79,24 +65,22 @@
android:layout_height="@dimen/biometric_auth_icon_size"
android:layout_gravity="center"
android:scaleType="fitXY"
- android:visibility="visible"
app:layout_constraintBottom_toTopOf="@+id/logo_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toTopOf="parent"
+ tools:visibility="visible" />
- <LinearLayout
- android:id="@+id/customized_view_container"
- android:layout_width="wrap_content"
+ <TextView
+ android:id="@+id/logo_description"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:paddingHorizontal="@dimen/biometric_prompt_content_container_padding_horizontal"
- android:visibility="gone"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:gravity="@integer/biometric_dialog_text_gravity"
+ android:singleLine="true"
+ app:layout_constraintBottom_toTopOf="@+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/subtitle" />
+ app:layout_constraintTop_toBottomOf="@+id/logo" />
<Space
android:id="@+id/space_above_content"
@@ -110,6 +94,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="@integer/biometric_dialog_text_gravity"
+ android:paddingTop="16dp"
app:layout_constraintBottom_toTopOf="@+id/subtitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -121,23 +106,24 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="@integer/biometric_dialog_text_gravity"
+ android:paddingTop="16dp"
app:layout_constraintBottom_toTopOf="@+id/contentBarrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
- <TextView
- android:id="@+id/logo_description"
+ <LinearLayout
+ android:id="@+id/customized_view_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:marqueeRepeatLimit="1"
- android:singleLine="true"
- app:layout_constraintBottom_toTopOf="@+id/title"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:visibility="gone"
+ android:paddingTop="8dp"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/logo" />
+ app:layout_constraintTop_toBottomOf="@+id/subtitle" />
<TextView
android:id="@+id/description"
@@ -145,6 +131,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="@integer/biometric_dialog_text_gravity"
+ android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -165,96 +152,17 @@
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
+ android:layout_marginTop="24dp"
android:accessibilityLiveRegion="polite"
android:fadingEdge="horizontal"
android:gravity="center_horizontal"
- android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
- android:textColor="@color/biometric_dialog_gray"
- android:textSize="12sp"
app:layout_constraintBottom_toTopOf="@+id/buttonBarrier"
app:layout_constraintEnd_toEndOf="@+id/panel"
app:layout_constraintStart_toStartOf="@+id/panel"
app:layout_constraintTop_toBottomOf="@+id/biometric_icon"
app:layout_constraintVertical_bias="0.0" />
- <!-- Negative Button, reserved for app -->
- <Button
- android:id="@+id/button_negative"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintStart_toStartOf="@+id/panel" />
-
- <!-- Cancel Button, replaces negative button when biometric is accepted -->
- <Button
- android:id="@+id/button_cancel"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:text="@string/cancel"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintStart_toStartOf="@+id/panel" />
-
- <!-- "Use Credential" Button, replaces if device credential is allowed -->
- <Button
- android:id="@+id/button_use_credential"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintStart_toStartOf="@+id/panel" />
-
- <!-- Positive Button -->
- <Button
- android:id="@+id/button_confirm"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginRight="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/biometric_dialog_confirm"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintEnd_toEndOf="@+id/panel"
- tools:visibility="invisible" />
-
- <!-- Try Again Button -->
- <Button
- android:id="@+id/button_try_again"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="8dp"
- android:layout_marginRight="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/biometric_dialog_try_again"
- android:visibility="invisible"
- app:layout_constraintBottom_toBottomOf="@+id/panel"
- app:layout_constraintEnd_toEndOf="@+id/panel" />
-
- <!-- Guidelines for setting panel border -->
<androidx.constraintlayout.widget.Barrier
android:id="@+id/topBarrier"
android:layout_width="wrap_content"
@@ -269,21 +177,21 @@
android:layout_height="wrap_content"
app:barrierAllowsGoneWidgets="false"
app:barrierDirection="top"
- app:constraint_referenced_ids="button_negative, button_cancel, button_use_credential, button_confirm, button_try_again" />
+ app:constraint_referenced_ids="button_bar" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/leftGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- app:layout_constraintGuide_begin="@dimen/biometric_dialog_border_padding" />
+ app:layout_constraintGuide_begin="0dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/rightGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" />
+ app:layout_constraintGuide_end="0dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/bottomGuideline"
@@ -297,6 +205,29 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
- app:layout_constraintGuide_percent="0.25171" />
+ app:layout_constraintGuide_percent="0.25" />
+
+ <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
+ android:id="@+id/biometric_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_bias="0.8"
+ tools:srcCompat="@tools:sample/avatars" />
+
+ <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
+ android:id="@+id/biometric_icon_overlay"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_gravity="center"
+ android:contentDescription="@null"
+ android:scaleType="fitXY"
+ app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
+ app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
+ app:layout_constraintStart_toStartOf="@+id/biometric_icon"
+ app:layout_constraintTop_toTopOf="@+id/biometric_icon" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index 8a19c2ebdcd6..4d207da851cd 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -100,7 +100,7 @@
app:layout_constraintStart_toStartOf="parent"
android:transitionName="screenshot_preview_image"/>
- <com.android.systemui.screenshot.CropView
+ <com.android.systemui.screenshot.scroll.CropView
android:id="@+id/crop_view"
android:layout_width="0px"
android:layout_height="0px"
@@ -122,7 +122,7 @@
tools:minHeight="100dp"
tools:minWidth="100dp" />
- <com.android.systemui.screenshot.MagnifierView
+ <com.android.systemui.screenshot.scroll.MagnifierView
android:id="@+id/magnifier"
android:visibility="invisible"
android:layout_width="200dp"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b7eff38aa015..76465c6e5011 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1087,7 +1087,7 @@
<dimen name="biometric_dialog_fingerprint_icon_height">80dp</dimen>
<dimen name="biometric_dialog_button_negative_max_width">160dp</dimen>
<dimen name="biometric_dialog_button_positive_max_width">136dp</dimen>
- <dimen name="biometric_dialog_corner_size">4dp</dimen>
+ <dimen name="biometric_dialog_corner_size">28dp</dimen>
<!-- Y translation when showing/dismissing the dialog-->
<dimen name="biometric_dialog_animation_translation_offset">350dp</dimen>
<dimen name="biometric_dialog_border_padding">4dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e3a5e156b055..774bbe504b03 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3358,7 +3358,7 @@
<string name="microphone_blocked_dream_overlay_content_description">Microphone blocked</string>
<!-- Content description for priority mode icon on dream [CHAR LIMIT=NONE] -->
- <string name="priority_mode_dream_overlay_content_description">Priority mode on</string>
+ <string name="priority_mode_dream_overlay_content_description">Do not disturb</string>
<!-- Content description for when assistant attention is active [CHAR LIMIT=NONE] -->
<string name="assistant_attention_content_description">User presence is detected</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 0bb5c174444f..fb331b62369e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -15,8 +15,10 @@
*/
package com.android.keyguard;
+import android.annotation.NonNull;
import android.app.Presentation;
import android.content.Context;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
@@ -315,11 +317,11 @@ public class KeyguardDisplayManager {
}
@Override
- public void onStateChanged(int state) {
+ public void onDeviceStateChanged(@NonNull DeviceState state) {
// When concurrent state ends, the display also turns off. This is enforced in various
// ExtensionRearDisplayPresentationTest CTS tests. So, we don't need to invoke
// hide() since that will happen through the onDisplayRemoved callback.
- mIsInConcurrentDisplayState = state == mConcurrentState;
+ mIsInConcurrentDisplayState = state.getIdentifier() == mConcurrentState;
}
boolean isConcurrentDisplayActive(Display display) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 8bd675c44943..99cdc0181553 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -340,13 +340,19 @@ public class AuthContainerView extends LinearLayout
mPanelInteractionDetector = panelInteractionDetector;
mApplicationCoroutineScope = applicationCoroutineScope;
+ mPromptViewModel = promptViewModel;
mTranslationY = getResources()
.getDimension(R.dimen.biometric_dialog_animation_translation_offset);
mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
mBiometricCallback = new BiometricCallback();
+ mPromptSelectorInteractorProvider = promptSelectorInteractorProvider;
+ mPromptSelectorInteractorProvider.get().setShouldShowBpWithoutIconForCredential(
+ config.mPromptInfo);
+
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
- if (constraintBp()) {
+ if (constraintBp() && (Utils.isBiometricAllowed(config.mPromptInfo)
+ || mPromptViewModel.getShowBpWithoutIconForCredential().getValue())) {
mLayout = (ConstraintLayout) layoutInflater.inflate(
R.layout.biometric_prompt_constraint_layout, this, false /* attachToRoot */);
} else {
@@ -375,9 +381,7 @@ public class AuthContainerView extends LinearLayout
mBackgroundExecutor = bgExecutor;
mInteractionJankMonitor = jankMonitor;
mPromptCredentialInteractor = credentialInteractor;
- mPromptSelectorInteractorProvider = promptSelectorInteractorProvider;
mCredentialViewModelProvider = credentialViewModelProvider;
- mPromptViewModel = promptViewModel;
mFpProps = fpProps;
mFaceProps = faceProps;
@@ -408,10 +412,6 @@ public class AuthContainerView extends LinearLayout
@Nullable FaceSensorPropertiesInternal faceProps,
@NonNull VibratorHelper vibratorHelper
) {
- // Set this value before showing either of the prompt.
- mPromptSelectorInteractorProvider.get().setShouldShowBpWithoutIconForCredential(
- config.mPromptInfo);
-
if (Utils.isBiometricAllowed(config.mPromptInfo)
|| mPromptViewModel.getShowBpWithoutIconForCredential().getValue()) {
addBiometricView(config, layoutInflater, viewModel, fpProps, faceProps, vibratorHelper);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index 478ef8f296b2..1dfd2e5f9cc9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -23,6 +23,7 @@ import android.graphics.Outline
import android.graphics.Rect
import android.transition.AutoTransition
import android.transition.TransitionManager
+import android.util.TypedValue
import android.view.Surface
import android.view.View
import android.view.ViewGroup
@@ -54,13 +55,10 @@ import com.android.systemui.biometrics.ui.viewmodel.isNullOrNotSmall
import com.android.systemui.biometrics.ui.viewmodel.isRight
import com.android.systemui.biometrics.ui.viewmodel.isSmall
import com.android.systemui.biometrics.ui.viewmodel.isTop
-import com.android.systemui.keyguard.ui.view.layout.sections.setVisibility
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
-import kotlin.math.abs
import kotlin.math.min
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
/** Helper for [BiometricViewBinder] to handle resize transitions. */
@@ -106,6 +104,13 @@ object BiometricViewSizeBinder {
val iconHolderView = view.requireViewById<View>(R.id.biometric_icon)
val panelView = view.requireViewById<View>(R.id.panel)
val cornerRadius = view.resources.getDimension(R.dimen.biometric_dialog_corner_size)
+ val cornerRadiusPx =
+ TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ cornerRadius,
+ view.resources.displayMetrics
+ )
+ .toInt()
// ConstraintSets for animating between prompt sizes
val mediumConstraintSet = ConstraintSet()
@@ -116,9 +121,10 @@ object BiometricViewSizeBinder {
val largeConstraintSet = ConstraintSet()
largeConstraintSet.clone(mediumConstraintSet)
- largeConstraintSet.setGuidelineBegin(leftGuideline.id, 0)
- largeConstraintSet.setGuidelineEnd(rightGuideline.id, 0)
- largeConstraintSet.setGuidelineEnd(bottomGuideline.id, 0)
+ largeConstraintSet.setVisibility(iconHolderView.id, View.GONE)
+ largeConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE)
+ largeConstraintSet.setVisibility(R.id.indicator, View.GONE)
+ largeConstraintSet.setVisibility(R.id.scrollView, View.GONE)
// TODO: Investigate better way to handle 180 rotations
val flipConstraintSet = ConstraintSet()
@@ -141,7 +147,13 @@ object BiometricViewSizeBinder {
panelView.outlineProvider =
object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
- outline.setRoundRect(0, 0, view.width, view.height, cornerRadius)
+ outline.setRoundRect(
+ 0,
+ 0,
+ view.width,
+ view.height + cornerRadiusPx,
+ cornerRadiusPx.toFloat()
+ )
}
}
@@ -164,35 +176,81 @@ object BiometricViewSizeBinder {
when {
position.isTop -> {
+ // Round bottom corners
+ panelView.outlineProvider =
+ object : ViewOutlineProvider() {
+ override fun getOutline(view: View, outline: Outline) {
+ outline.setRoundRect(
+ 0,
+ -cornerRadiusPx,
+ view.width,
+ view.height,
+ cornerRadiusPx.toFloat()
+ )
+ }
+ }
left = windowBounds.centerX() - width / 2 + viewModel.promptMargin
right = windowBounds.centerX() - width / 2 + viewModel.promptMargin
bottom = iconHolderView.centerY() * 2 - iconHolderView.centerY() / 4
}
position.isBottom -> {
- left = windowBounds.centerX() - width / 2 + viewModel.promptMargin
- right = windowBounds.centerX() - width / 2 + viewModel.promptMargin
- bottom = viewModel.promptMargin
+ // Round top corners
+ panelView.outlineProvider =
+ object : ViewOutlineProvider() {
+ override fun getOutline(view: View, outline: Outline) {
+ outline.setRoundRect(
+ 0,
+ 0,
+ view.width,
+ view.height + cornerRadiusPx,
+ cornerRadiusPx.toFloat()
+ )
+ }
+ }
+
+ left = windowBounds.centerX() - width / 2
+ right = windowBounds.centerX() - width / 2
+ bottom = if (view.isLandscape()) bottomInset else 0
}
position.isLeft -> {
- left = viewModel.promptMargin
- mid =
- abs(
- windowBounds.width() - iconHolderView.centerX() * 2 +
- viewModel.promptMargin
- )
+ // Round right corners
+ panelView.outlineProvider =
+ object : ViewOutlineProvider() {
+ override fun getOutline(view: View, outline: Outline) {
+ outline.setRoundRect(
+ -cornerRadiusPx,
+ 0,
+ view.width,
+ view.height,
+ cornerRadiusPx.toFloat()
+ )
+ }
+ }
+
+ left = 0
+ mid = (windowBounds.width() * .85).toInt() / 2
right = windowBounds.width() - (windowBounds.width() * .85).toInt()
- bottom = bottomInset + viewModel.promptMargin
+ bottom = if (view.isLandscape()) bottomInset else 0
}
position.isRight -> {
+ // Round left corners
+ panelView.outlineProvider =
+ object : ViewOutlineProvider() {
+ override fun getOutline(view: View, outline: Outline) {
+ outline.setRoundRect(
+ 0,
+ 0,
+ view.width + cornerRadiusPx,
+ view.height,
+ cornerRadiusPx.toFloat()
+ )
+ }
+ }
+
left = windowBounds.width() - (windowBounds.width() * .85).toInt()
- right = viewModel.promptMargin
- bottom = bottomInset + viewModel.promptMargin
- mid =
- abs(
- iconHolderView.centerX() -
- (windowBounds.width() - iconHolderView.centerX()) -
- viewModel.promptMargin
- )
+ right = 0
+ bottom = if (view.isLandscape()) bottomInset else 0
+ mid = windowBounds.width() - (windowBounds.width() * .85).toInt() / 2
}
}
@@ -226,16 +284,8 @@ object BiometricViewSizeBinder {
}
}
- fun setConstraintSetVisibility() {
- viewsToHideWhenSmall.forEach {
- mediumConstraintSet.setVisibility(it.id, it.showContentOrHide())
- largeConstraintSet.setVisibility(it.id, View.GONE)
- smallConstraintSet.setVisibility(it.id, View.GONE)
- }
-
- largeConstraintSet.setVisibility(iconHolderView.id, View.GONE)
- largeConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE)
- largeConstraintSet.setVisibility(R.id.indicator, View.GONE)
+ fun setVisibilities(size: PromptSize) {
+ viewsToHideWhenSmall.forEach { it.showContentOrHide(forceHide = size.isSmall) }
if (viewModel.showBpWithoutIconForCredential.value) {
smallConstraintSet.setVisibility(iconHolderView.id, View.GONE)
@@ -261,7 +311,7 @@ object BiometricViewSizeBinder {
}
measureBounds(position)
- setConstraintSetVisibility()
+ setVisibilities(size)
when {
size.isSmall -> {
val ratio =
@@ -353,7 +403,7 @@ object BiometricViewSizeBinder {
// prepare for animated size transitions
for (v in viewsToHideWhenSmall) {
- v.visibility = v.showContentOrHide(forceHide = size.isSmall)
+ v.showContentOrHide(forceHide = size.isSmall)
}
if (viewModel.showBpWithoutIconForCredential.value) {
@@ -490,14 +540,15 @@ private fun View.isLandscape(): Boolean {
}
}
-private fun View.showContentOrHide(forceHide: Boolean = false): Int {
+private fun View.showContentOrHide(forceHide: Boolean = false) {
val isTextViewWithBlankText = this is TextView && this.text.isBlank()
val isImageViewWithoutImage = this is ImageView && this.drawable == null
- return if (forceHide || isTextViewWithBlankText || isImageViewWithoutImage) {
- View.GONE
- } else {
- View.VISIBLE
- }
+ visibility =
+ if (forceHide || isTextViewWithBlankText || isImageViewWithoutImage) {
+ View.GONE
+ } else {
+ View.VISIBLE
+ }
}
private fun View.centerX(): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
index e457601a6d52..d8265c7d40e8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
@@ -63,12 +63,6 @@ object PromptIconViewBinder {
iconOverlayView.layoutParams.width = iconViewLayoutParamSizeOverride.first
iconOverlayView.layoutParams.height = iconViewLayoutParamSizeOverride.second
- } else {
- iconView.layoutParams.width = viewModel.fingerprintIconWidth.first()
- iconView.layoutParams.height = viewModel.fingerprintIconWidth.first()
-
- iconOverlayView.layoutParams.width = viewModel.fingerprintIconWidth.first()
- iconOverlayView.layoutParams.height = viewModel.fingerprintIconWidth.first()
}
var faceIcon: AnimatedVectorDrawable? = null
@@ -84,10 +78,8 @@ object PromptIconViewBinder {
}
launch {
- var width = 0
- var height = 0
- combine(promptViewModel.size, viewModel.activeAuthType, ::Pair).collect {
- (_, activeAuthType) ->
+ combine(viewModel.activeAuthType, viewModel.iconSize, ::Pair).collect {
+ (activeAuthType, iconSize) ->
// Every time after bp shows, [isIconViewLoaded] is set to false in
// [BiometricViewSizeBinder]. Then when biometric prompt view is redrew
// (when size or activeAuthType changes), we need to update
@@ -109,8 +101,6 @@ object PromptIconViewBinder {
}
}
AuthType.Face -> {
- width = viewModel.faceIconWidth
- height = viewModel.faceIconHeight
/**
* Set to true by default since face icon is a drawable, which
* doesn't have a LottieOnCompositionLoadedListener equivalent.
@@ -122,11 +112,12 @@ object PromptIconViewBinder {
}
}
- if (width != 0 && height != 0) {
- iconView.layoutParams.width = width
- iconView.layoutParams.height = height
- iconOverlayView.layoutParams.width = width
- iconOverlayView.layoutParams.height = height
+ if (iconViewLayoutParamSizeOverride == null) {
+ iconView.layoutParams.width = iconSize.first
+ iconView.layoutParams.height = iconSize.second
+
+ iconOverlayView.layoutParams.width = iconSize.first
+ iconOverlayView.layoutParams.height = iconSize.second
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt
index 257eb4a60328..d0c140b353e2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt
@@ -21,6 +21,7 @@ import android.annotation.DrawableRes
import android.annotation.RawRes
import android.content.res.Configuration
import android.graphics.Rect
+import android.hardware.face.Face
import android.util.RotationUtils
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
@@ -65,9 +66,10 @@ constructor(
*/
val activeAuthType: Flow<AuthType> =
combine(
+ promptViewModel.size,
promptViewModel.modalities.distinctUntilChanged(),
promptViewModel.faceMode.distinctUntilChanged()
- ) { modalities, faceMode ->
+ ) { _, modalities, faceMode ->
if (modalities.hasFaceAndFingerprint && !faceMode) {
AuthType.Coex
} else if (modalities.hasFaceOnly || faceMode) {
@@ -158,13 +160,18 @@ constructor(
/** Tracks whether a face iconView last pulsed light to dark (vs. dark to light) */
val lastPulseLightToDark: Flow<Boolean> = _lastPulseLightToDark.asStateFlow()
- /** Layout params for fingerprint iconView */
- val fingerprintIconWidth: Flow<Int> = promptViewModel.fingerprintSensorDiameter
- val fingerprintIconHeight: Flow<Int> = promptViewModel.fingerprintSensorDiameter
-
- /** Layout params for face iconView */
- val faceIconWidth: Int = promptViewModel.faceIconWidth
- val faceIconHeight: Int = promptViewModel.faceIconHeight
+ val iconSize: Flow<Pair<Int, Int>> =
+ combine(
+ activeAuthType,
+ promptViewModel.fingerprintSensorWidth,
+ promptViewModel.fingerprintSensorHeight,
+ ) { activeAuthType, fingerprintSensorWidth, fingerprintSensorHeight ->
+ if (activeAuthType == AuthType.Face) {
+ Pair(promptViewModel.faceIconWidth, promptViewModel.faceIconHeight)
+ } else {
+ Pair(fingerprintSensorWidth, fingerprintSensorHeight)
+ }
+ }
/** Current BiometricPromptLayout.iconView asset. */
val iconAsset: Flow<Int> =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 86b0b4455f61..fbd87fd3a9f5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -86,7 +86,7 @@ constructor(
val faceIconHeight: Int =
context.resources.getDimensionPixelSize(R.dimen.biometric_dialog_face_icon_size)
- val fingerprintSensorDiameter: Flow<Int> =
+ val fingerprintSensorWidth: Flow<Int> =
combine(modalities, udfpsOverlayInteractor.udfpsOverlayParams) { modalities, overlayParams
->
if (modalities.hasUdfps) {
@@ -96,6 +96,16 @@ constructor(
}
}
+ val fingerprintSensorHeight: Flow<Int> =
+ combine(modalities, udfpsOverlayInteractor.udfpsOverlayParams) { modalities, overlayParams
+ ->
+ if (modalities.hasUdfps) {
+ overlayParams.sensorBounds.height()
+ } else {
+ fingerprintIconHeight
+ }
+ }
+
private val _accessibilityHint = MutableSharedFlow<String>()
/** Hint for talkback directional guidance */
@@ -342,7 +352,7 @@ constructor(
position,
message,
) { size, _, message ->
- size.isNotSmall && message.message.isNotBlank()
+ size.isMedium && message.message.isNotBlank()
}
/** If the auth is pending confirmation and the confirm button should be shown. */
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 9afd5ede0b4c..d2df276002cc 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -24,9 +24,9 @@ import com.android.systemui.contrast.ContrastDialogActivity;
import com.android.systemui.keyguard.WorkLockActivity;
import com.android.systemui.people.PeopleSpaceActivity;
import com.android.systemui.people.widget.LaunchConversationActivity;
-import com.android.systemui.screenshot.LongScreenshotActivity;
import com.android.systemui.screenshot.appclips.AppClipsActivity;
import com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity;
+import com.android.systemui.screenshot.scroll.LongScreenshotActivity;
import com.android.systemui.sensorprivacy.SensorUseStartedActivity;
import com.android.systemui.settings.brightness.BrightnessDialog;
import com.android.systemui.telephony.ui.activity.SwitchToManagedProfileForCallActivity;
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
index 83337f760c33..fa7603ff777c 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
@@ -62,7 +62,7 @@ constructor(
conflatedCallbackFlow {
val callback =
DeviceStateManager.DeviceStateCallback { state ->
- trySend(deviceStateToPosture(state))
+ trySend(deviceStateToPosture(state.identifier))
}
deviceStateManager.registerCallback(executor, callback)
awaitClose { deviceStateManager.unregisterCallback(callback) }
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 1d820a14be4e..5f0635bdba01 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -21,6 +21,9 @@ import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS;
import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
+import static android.appwidget.flags.Flags.generatedPreviews;
import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
@@ -80,12 +83,15 @@ import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseBooleanArray;
import android.widget.RemoteViews;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dumpable;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
@@ -96,6 +102,8 @@ import com.android.systemui.people.PeopleBackupFollowUpJob;
import com.android.systemui.people.PeopleSpaceUtils;
import com.android.systemui.people.PeopleTileViewHelper;
import com.android.systemui.people.SharedPreferencesHelper;
+import com.android.systemui.res.R;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -160,13 +168,27 @@ public class PeopleSpaceWidgetManager implements Dumpable {
@GuardedBy("mLock")
public static Map<Integer, PeopleSpaceTile> mTiles = new HashMap<>();
+ @NonNull private final UserTracker mUserTracker;
+ @NonNull private final SparseBooleanArray mUpdatedPreviews = new SparseBooleanArray();
+ @NonNull private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onUserUnlocked() {
+ if (DEBUG) {
+ Log.d(TAG, "onUserUnlocked " + mUserTracker.getUserId());
+ }
+ updateGeneratedPreviewForUser(mUserTracker.getUserHandle());
+ }
+ };
+
@Inject
public PeopleSpaceWidgetManager(Context context, LauncherApps launcherApps,
CommonNotifCollection notifCollection,
PackageManager packageManager, Optional<Bubbles> bubblesOptional,
UserManager userManager, NotificationManager notificationManager,
BroadcastDispatcher broadcastDispatcher, @Background Executor bgExecutor,
- DumpManager dumpManager) {
+ DumpManager dumpManager, @NonNull UserTracker userTracker,
+ @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor) {
if (DEBUG) Log.d(TAG, "constructor");
mContext = context;
mAppWidgetManager = AppWidgetManager.getInstance(context);
@@ -187,6 +209,8 @@ public class PeopleSpaceWidgetManager implements Dumpable {
mBroadcastDispatcher = broadcastDispatcher;
mBgExecutor = bgExecutor;
dumpManager.registerNormalDumpable(TAG, this);
+ mUserTracker = userTracker;
+ keyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
}
/** Initializes {@PeopleSpaceWidgetManager}. */
@@ -246,7 +270,7 @@ public class PeopleSpaceWidgetManager implements Dumpable {
CommonNotifCollection notifCollection, PackageManager packageManager,
Optional<Bubbles> bubblesOptional, UserManager userManager, BackupManager backupManager,
INotificationManager iNotificationManager, NotificationManager notificationManager,
- @Background Executor executor) {
+ @Background Executor executor, UserTracker userTracker) {
mContext = context;
mAppWidgetManager = appWidgetManager;
mIPeopleManager = iPeopleManager;
@@ -262,6 +286,7 @@ public class PeopleSpaceWidgetManager implements Dumpable {
mManager = this;
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
mBgExecutor = executor;
+ mUserTracker = userTracker;
}
/**
@@ -1407,4 +1432,24 @@ public class PeopleSpaceWidgetManager implements Dumpable {
Trace.traceEnd(Trace.TRACE_TAG_APP);
}
+
+ @VisibleForTesting
+ void updateGeneratedPreviewForUser(UserHandle user) {
+ if (!generatedPreviews() || mUpdatedPreviews.get(user.getIdentifier())
+ || !mUserManager.isUserUnlocked(user)) {
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Updating People Space widget preview for user " + user.getIdentifier());
+ }
+ boolean success = mAppWidgetManager.setWidgetPreview(
+ new ComponentName(mContext, PeopleSpaceWidgetProvider.class),
+ WIDGET_CATEGORY_HOME_SCREEN | WIDGET_CATEGORY_KEYGUARD,
+ new RemoteViews(mContext.getPackageName(),
+ R.layout.people_space_placeholder_layout));
+ if (DEBUG && !success) {
+ Log.d(TAG, "Failed to update generated preview for user " + user.getIdentifier());
+ }
+ mUpdatedPreviews.put(user.getIdentifier(), success);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt
index aed08f8b5457..4a8e33a99b25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt
@@ -37,7 +37,11 @@ sealed class TileSpec private constructor(open val spec: String) {
data class PlatformTileSpec
internal constructor(
override val spec: String,
- ) : TileSpec(spec)
+ ) : TileSpec(spec) {
+ override fun toString(): String {
+ return "P($spec)"
+ }
+ }
/**
* Container for the spec of a tile provided by an app.
@@ -50,7 +54,7 @@ sealed class TileSpec private constructor(open val spec: String) {
val componentName: ComponentName,
) : TileSpec(spec) {
override fun toString(): String {
- return "CustomTileSpec(${componentName.toShortString()})"
+ return "C(${componentName.flattenToShortString()})"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java
index 9076182def70..f02b871b196d 100644
--- a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java
@@ -16,12 +16,14 @@
package com.android.systemui.reardisplay;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManagerGlobal;
import android.view.LayoutInflater;
@@ -29,7 +31,6 @@ import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -179,6 +180,7 @@ public class RearDisplayDialogController implements
*/
private void initializeValues(int startingBaseState) {
mRearDisplayEducationDialog = mSystemUIDialogFactory.create();
+ // TODO(b/329170810): Refactor and remove with updated DeviceStateManager values.
if (mFoldedStates == null) {
mFoldedStates = mResources.getIntArray(
com.android.internal.R.array.config_foldedDeviceStates);
@@ -228,21 +230,19 @@ public class RearDisplayDialogController implements
private class DeviceStateManagerCallback implements DeviceStateManager.DeviceStateCallback {
@Override
- public void onBaseStateChanged(int state) {
- if (mStartedFolded && !isFoldedState(state)) {
+ public void onDeviceStateChanged(@NonNull DeviceState state) {
+ if (mStartedFolded && !state.hasProperty(
+ DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)) {
// We've opened the device, we can close the overlay
mRearDisplayEducationDialog.dismiss();
closeOverlayAndNotifyService(false);
- } else if (!mStartedFolded && isFoldedState(state)) {
+ } else if (!mStartedFolded && state.hasProperty(
+ DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)) {
// We've closed the device, finish activity
mRearDisplayEducationDialog.dismiss();
closeOverlayAndNotifyService(true);
}
}
-
- // We only care about physical device changes in this scenario
- @Override
- public void onStateChanged(int state) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index c4287ca899dc..864f29a5c5e0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -126,7 +126,7 @@ public class ImageExporter {
/**
* Writes the given Bitmap to outputFile.
*/
- ListenableFuture<File> exportToRawFile(Executor executor, Bitmap bitmap,
+ public ListenableFuture<File> exportToRawFile(Executor executor, Bitmap bitmap,
final File outputFile) {
return CallbackToFutureAdapter.getFuture(
(completer) -> {
@@ -196,7 +196,7 @@ public class ImageExporter {
* @param bitmap the bitmap to export
* @return a listenable future result
*/
- ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
+ public ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
ZonedDateTime captureTime, UserHandle owner, int displayId) {
return export(executor, new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
mQuality, /* publish */ true, owner, mFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
index 1f6d2122ebfc..a1481f6d6d2b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
@@ -34,6 +34,7 @@ import androidx.appcompat.content.res.AppCompatResources
import com.android.internal.logging.UiEventLogger
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.res.R
+import com.android.systemui.screenshot.scroll.ScrollCaptureController
import com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER
import dagger.assisted.Assisted
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LogConfig.java b/packages/SystemUI/src/com/android/systemui/screenshot/LogConfig.java
index 6050c2b90e34..440cf1c344da 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LogConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LogConfig.java
@@ -16,8 +16,9 @@
package com.android.systemui.screenshot;
+/** Stores debug log configuration for screenshots. */
@SuppressWarnings("PointlessBooleanExpression")
-class LogConfig {
+public class LogConfig {
/** Log ALL the things... */
private static final boolean DEBUG_ALL = false;
@@ -29,36 +30,37 @@ class LogConfig {
private static final boolean TAG_WITH_CLASS_NAME = false;
/** Action creation and user selection: Share, Save, Edit, Delete, Smart action, etc */
- static final boolean DEBUG_ACTIONS = DEBUG_ALL || false;
+ public static final boolean DEBUG_ACTIONS = DEBUG_ALL || false;
/** Debug info about animations such as start, complete and cancel */
- static final boolean DEBUG_ANIM = DEBUG_ALL || false;
+ public static final boolean DEBUG_ANIM = DEBUG_ALL || false;
/** Whenever Uri is supplied to consumer, or onComplete runnable is run() */
- static final boolean DEBUG_CALLBACK = DEBUG_ALL || false;
+ public static final boolean DEBUG_CALLBACK = DEBUG_ALL || false;
/** Logs information about dismissing the screenshot tool */
- static final boolean DEBUG_DISMISS = DEBUG_ALL || false;
+ public static final boolean DEBUG_DISMISS = DEBUG_ALL || false;
/** Touch or key event driven action or side effects */
- static final boolean DEBUG_INPUT = DEBUG_ALL || false;
+ public static final boolean DEBUG_INPUT = DEBUG_ALL || false;
/** Scroll capture usage */
- static final boolean DEBUG_SCROLL = DEBUG_ALL || false;
+ public static final boolean DEBUG_SCROLL = DEBUG_ALL || false;
/** Service lifecycle events and callbacks */
- static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
+ public static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
/** Storage related actions, Bitmap.compress, ContentManager, etc */
- static final boolean DEBUG_STORAGE = DEBUG_ALL || false;
+ public static final boolean DEBUG_STORAGE = DEBUG_ALL || false;
/** High level logical UI actions: timeout, onConfigChanged, insets, show actions, reset */
- static final boolean DEBUG_UI = DEBUG_ALL || false;
+ public static final boolean DEBUG_UI = DEBUG_ALL || false;
/** Interactions with Window and WindowManager */
- static final boolean DEBUG_WINDOW = DEBUG_ALL || false;
+ public static final boolean DEBUG_WINDOW = DEBUG_ALL || false;
- static String logTag(Class<?> cls) {
+ /** Get the appropriate class name */
+ public static String logTag(Class<?> cls) {
return TAG_WITH_CLASS_NAME ? cls.getSimpleName() : TAG_SS;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 198a29c4ed5b..c8e13bb8c2fc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -87,6 +87,10 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.res.R;
import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
+import com.android.systemui.screenshot.scroll.LongScreenshotActivity;
+import com.android.systemui.screenshot.scroll.LongScreenshotData;
+import com.android.systemui.screenshot.scroll.ScrollCaptureClient;
+import com.android.systemui.screenshot.scroll.ScrollCaptureController;
import com.android.systemui.util.Assert;
import com.google.common.util.concurrent.ListenableFuture;
@@ -200,7 +204,7 @@ public class ScreenshotController {
void onActionsReady(ScreenshotController.QuickShareData quickShareData);
}
- interface TransitionDestination {
+ public interface TransitionDestination {
/**
* Allows the long screenshot activity to call back with a destination location (the bounds
* on screen of the destination for the transitioning view) and a Runnable to be run once
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 1c5a8a1a9fd3..cb2dba00890b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -92,6 +92,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.res.R;
+import com.android.systemui.screenshot.scroll.ScrollCaptureController;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
index 182b8894677a..6be32a97f4e2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
@@ -25,6 +25,7 @@ import android.view.ScrollCaptureResponse
import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
+import com.android.systemui.screenshot.scroll.ScrollCaptureController
/** Abstraction of the surface between ScreenshotController and ScreenshotView */
interface ScreenshotViewProxy {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
index aa23d6bed5e1..d87d85b93b9d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
@@ -52,7 +52,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLogger.UiEventEnum;
import com.android.settingslib.Utils;
import com.android.systemui.res.R;
-import com.android.systemui.screenshot.CropView;
+import com.android.systemui.screenshot.scroll.CropView;
import com.android.systemui.settings.UserTracker;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java
index 2f411ea3cb33..5e561cfb14a1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -265,7 +265,7 @@ public class CropView extends View {
Log.w(TAG, "No boundary selected");
break;
}
- Log.i(TAG, "Updated mCrop: " + mCrop);
+ Log.i(TAG, "Updated mCrop: " + mCrop);
invalidate();
}
@@ -385,7 +385,7 @@ public class CropView extends View {
/**
* @param action either ACTION_DOWN, ACTION_UP or ACTION_MOVE.
- * @param x coordinate of the relevant pointer.
+ * @param x x-coordinate of the relevant pointer.
*/
private void updateListener(int action, float x) {
if (mCropInteractionListener != null && isVertical(mCurrentDraggingBoundary)) {
@@ -643,11 +643,13 @@ public class CropView extends View {
/**
* Listen for crop motion events and state.
*/
- public interface CropInteractionListener {
+ interface CropInteractionListener {
void onCropDragStarted(CropBoundary boundary, float boundaryPosition,
int boundaryPositionPx, float horizontalCenter, float x);
+
void onCropDragMoved(CropBoundary boundary, float boundaryPosition,
int boundaryPositionPx, float horizontalCenter, float x);
+
void onCropDragComplete();
}
@@ -675,8 +677,7 @@ public class CropView extends View {
out.writeParcelable(mCrop, 0);
}
- public static final Parcelable.Creator<SavedState> CREATOR
- = new Parcelable.Creator<SavedState>() {
+ public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageLoader.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageLoader.java
index 7ee7c319799c..df86d69b2527 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -35,20 +35,20 @@ import java.io.InputStream;
import javax.inject.Inject;
/** Loads images. */
-public class ImageLoader {
+class ImageLoader {
private final ContentResolver mResolver;
static class Result {
- @Nullable Uri uri;
- @Nullable File fileName;
- @Nullable Bitmap bitmap;
+ @Nullable Uri mUri;
+ @Nullable File mFilename;
+ @Nullable Bitmap mBitmap;
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Result{");
- sb.append("uri=").append(uri);
- sb.append(", fileName=").append(fileName);
- sb.append(", bitmap=").append(bitmap);
+ sb.append("uri=").append(mUri);
+ sb.append(", fileName=").append(mFilename);
+ sb.append(", bitmap=").append(mBitmap);
sb.append('}');
return sb.toString();
}
@@ -69,11 +69,10 @@ public class ImageLoader {
return CallbackToFutureAdapter.getFuture(completer -> {
Result result = new Result();
try (InputStream in = mResolver.openInputStream(uri)) {
- result.uri = uri;
- result.bitmap = BitmapFactory.decodeStream(in);
+ result.mUri = uri;
+ result.mBitmap = BitmapFactory.decodeStream(in);
completer.set(result);
- }
- catch (IOException e) {
+ } catch (IOException e) {
completer.setException(e);
}
return "BitmapFactory#decodeStream";
@@ -91,8 +90,8 @@ public class ImageLoader {
return CallbackToFutureAdapter.getFuture(completer -> {
try (InputStream in = new BufferedInputStream(new FileInputStream(file))) {
Result result = new Result();
- result.fileName = file;
- result.bitmap = BitmapFactory.decodeStream(in);
+ result.mFilename = file;
+ result.mBitmap = BitmapFactory.decodeStream(in);
completer.set(result);
} catch (IOException e) {
completer.setException(e);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTile.java
index a95c91bfeceb..c9c297e53bd4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTile.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import static android.graphics.ColorSpace.Named.SRGB;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTileSet.java
index 356f67e7ea00..76a72f7e4adf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTileSet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import android.annotation.AnyThread;
import android.graphics.Bitmap;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotActivity.java
index 00d480a76355..1e1a577ebd4a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import android.app.Activity;
import android.app.ActivityOptions;
@@ -47,11 +47,14 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.view.OneShotPreDrawListener;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.res.R;
-import com.android.systemui.screenshot.CropView.CropBoundary;
-import com.android.systemui.screenshot.ScrollCaptureController.LongScreenshot;
-import com.android.systemui.settings.UserTracker;
+import com.android.systemui.screenshot.ActionIntentCreator;
+import com.android.systemui.screenshot.ActionIntentExecutor;
+import com.android.systemui.screenshot.ImageExporter;
+import com.android.systemui.screenshot.LogConfig;
+import com.android.systemui.screenshot.ScreenshotEvent;
+import com.android.systemui.screenshot.scroll.CropView.CropBoundary;
+import com.android.systemui.screenshot.scroll.ScrollCaptureController.LongScreenshot;
import com.google.common.util.concurrent.ListenableFuture;
@@ -81,8 +84,6 @@ public class LongScreenshotActivity extends Activity {
private final ImageExporter mImageExporter;
private final LongScreenshotData mLongScreenshotHolder;
private final ActionIntentExecutor mActionExecutor;
- private final FeatureFlags mFeatureFlags;
- private final UserTracker mUserTracker;
private ImageView mPreview;
private ImageView mTransitionView;
@@ -113,16 +114,13 @@ public class LongScreenshotActivity extends Activity {
@Inject
public LongScreenshotActivity(UiEventLogger uiEventLogger, ImageExporter imageExporter,
@Main Executor mainExecutor, @Background Executor bgExecutor,
- LongScreenshotData longScreenshotHolder, ActionIntentExecutor actionExecutor,
- FeatureFlags featureFlags, UserTracker userTracker) {
+ LongScreenshotData longScreenshotHolder, ActionIntentExecutor actionExecutor) {
mUiEventLogger = uiEventLogger;
mUiExecutor = mainExecutor;
mBackgroundExecutor = bgExecutor;
mImageExporter = imageExporter;
mLongScreenshotHolder = longScreenshotHolder;
mActionExecutor = actionExecutor;
- mFeatureFlags = featureFlags;
- mUserTracker = userTracker;
}
@@ -265,13 +263,13 @@ public class LongScreenshotActivity extends Activity {
private void onCachedImageLoaded(ImageLoader.Result imageResult) {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_CACHED_IMAGE_LOADED);
- BitmapDrawable drawable = new BitmapDrawable(getResources(), imageResult.bitmap);
+ BitmapDrawable drawable = new BitmapDrawable(getResources(), imageResult.mBitmap);
mPreview.setImageDrawable(drawable);
mPreview.setAlpha(1f);
- mMagnifierView.setDrawable(drawable, imageResult.bitmap.getWidth(),
- imageResult.bitmap.getHeight());
+ mMagnifierView.setDrawable(drawable, imageResult.mBitmap.getWidth(),
+ imageResult.mBitmap.getHeight());
mCropView.setVisibility(View.VISIBLE);
- mSavedImagePath = imageResult.fileName;
+ mSavedImagePath = imageResult.mFilename;
setButtonsEnabled(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotData.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotData.java
index f549faf2414a..ebac5bf2debd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotData.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.screenshot.ScreenshotController;
import java.util.concurrent.atomic.AtomicReference;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/MagnifierView.java
index 0c543cd8909c..0a1a74735648 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/MagnifierView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -64,16 +64,16 @@ public class MagnifierView extends View implements CropView.CropInteractionListe
private ViewPropertyAnimator mTranslationAnimator;
private final Animator.AnimatorListener mTranslationAnimatorListener =
new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- mTranslationAnimator = null;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mTranslationAnimator = null;
- }
- };
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mTranslationAnimator = null;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTranslationAnimator = null;
+ }
+ };
public MagnifierView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ScrollCaptureClient.java
index e93f737308ba..0e4334314ec2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ScrollCaptureClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import static com.android.systemui.screenshot.LogConfig.DEBUG_SCROLL;
@@ -46,6 +46,7 @@ import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.screenshot.LogConfig;
import com.google.common.util.concurrent.ListenableFuture;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ScrollCaptureController.java
index 8a2678c8ab09..f4c77da674b0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ScrollCaptureController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import android.content.Context;
import android.graphics.Bitmap;
@@ -30,8 +30,10 @@ import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
-import com.android.systemui.screenshot.ScrollCaptureClient.Session;
+import com.android.systemui.screenshot.LogConfig;
+import com.android.systemui.screenshot.ScreenshotEvent;
+import com.android.systemui.screenshot.scroll.ScrollCaptureClient.CaptureResult;
+import com.android.systemui.screenshot.scroll.ScrollCaptureClient.Session;
import com.google.common.util.concurrent.ListenableFuture;
@@ -85,7 +87,7 @@ public class ScrollCaptureController {
mImageTileSet = imageTileSet;
}
- /** Returns a bitmap containing the combinded result. */
+ /** Returns a bitmap containing the combined result. */
public Bitmap toBitmap() {
return mImageTileSet.toBitmap();
}
@@ -167,7 +169,7 @@ public class ScrollCaptureController {
* {@link ScrollCaptureResponse#isConnected() connected}.
* @return a future ImageTile set containing the result
*/
- ListenableFuture<LongScreenshot> run(ScrollCaptureResponse response) {
+ public ListenableFuture<LongScreenshot> run(ScrollCaptureResponse response) {
mCancelled = false;
return CallbackToFutureAdapter.getFuture(completer -> {
mCaptureCompleter = completer;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/TiledImageDrawable.java
index 71df369aa7b8..00455bcfbd99 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/TiledImageDrawable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import android.annotation.Nullable;
import android.graphics.Canvas;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt
index 56b0d598a512..db237e89a683 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone
import android.content.Context
+import android.hardware.devicestate.DeviceState
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback
import com.android.internal.R
@@ -45,13 +46,13 @@ internal class FoldStateListener(
private var wasFolded: Boolean? = null
- override fun onStateChanged(state: Int) {
- val isFolded = foldedDeviceStates.contains(state)
+ override fun onDeviceStateChanged(state: DeviceState) {
+ val isFolded = foldedDeviceStates.contains(state.identifier)
if (wasFolded == isFolded) {
return
}
wasFolded = isFolded
- val willGoToSleep = goToSleepDeviceStates.contains(state)
+ val willGoToSleep = goToSleepDeviceStates.contains(state.identifier)
listener.onFoldStateChanged(isFolded, willGoToSleep)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
index 422aa4d4aa60..de0eb493c83d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
@@ -16,12 +16,13 @@
package com.android.systemui.statusbar.policy;
+import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceStateUtil;
import android.util.SparseIntArray;
-import androidx.annotation.NonNull;
-
import com.android.app.tracing.ListenersTracing;
import com.android.internal.R;
import com.android.systemui.dagger.SysUISingleton;
@@ -42,8 +43,9 @@ public class DevicePostureControllerImpl implements DevicePostureController {
/** From androidx.window.common.COMMON_STATE_USE_BASE_STATE */
private static final int COMMON_STATE_USE_BASE_STATE = 1000;
private final List<Callback> mListeners = new ArrayList<>();
+ private final List<DeviceState> mSupportedStates;
+ private DeviceState mCurrentDeviceState;
private int mCurrentDevicePosture = DEVICE_POSTURE_UNKNOWN;
- private int mCurrentBasePosture = DEVICE_POSTURE_UNKNOWN;
private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
@@ -76,21 +78,17 @@ public class DevicePostureControllerImpl implements DevicePostureController {
mDeviceStateToPostureMap.put(deviceState, posture);
}
+ mSupportedStates = deviceStateManager.getSupportedDeviceStates();
deviceStateManager.registerCallback(executor, new DeviceStateManager.DeviceStateCallback() {
@Override
- public void onStateChanged(int state) {
- Assert.isMainThread();
- mCurrentDevicePosture =
- mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
- sendUpdatePosture();
- }
-
- @Override
- public void onBaseStateChanged(int state) {
+ public void onDeviceStateChanged(@NonNull DeviceState state) {
+ mCurrentDeviceState = state;
Assert.isMainThread();
- mCurrentBasePosture = mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
-
- if (useBaseState()) {
+ int newDevicePosture =
+ mDeviceStateToPostureMap.get(state.getIdentifier(), DEVICE_POSTURE_UNKNOWN);
+ if (newDevicePosture != mCurrentDevicePosture
+ || newDevicePosture == COMMON_STATE_USE_BASE_STATE) {
+ mCurrentDevicePosture = newDevicePosture;
sendUpdatePosture();
}
}
@@ -120,7 +118,8 @@ public class DevicePostureControllerImpl implements DevicePostureController {
@Override
public int getDevicePosture() {
if (useBaseState()) {
- return mCurrentBasePosture;
+ return DeviceStateUtil.calculateBaseStateIdentifier(mCurrentDeviceState,
+ mSupportedStates);
} else {
return mCurrentDevicePosture;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
index 3008c866d207..88cf46a0ca07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -20,6 +20,7 @@ import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORE
import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED;
import android.annotation.Nullable;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Trace;
import android.util.IndentingPrintWriter;
@@ -120,18 +121,18 @@ public final class DeviceStateRotationLockSettingController
mDeviceStateRotationLockSettingsManager.updateSetting(deviceState, isRotationLocked);
}
- private void updateDeviceState(int state) {
- mLogger.logUpdateDeviceState(mDeviceState, state);
- if (Trace.isEnabled()) {
- Trace.traceBegin(
- Trace.TRACE_TAG_APP, "updateDeviceState [state=" + state + "]");
- }
+ private void updateDeviceState(@NonNull DeviceState state) {
+ mLogger.logUpdateDeviceState(mDeviceState, state.getIdentifier());
try {
- if (mDeviceState == state) {
+ if (Trace.isEnabled()) {
+ Trace.traceBegin(Trace.TRACE_TAG_APP,
+ "updateDeviceState [state=" + state.getIdentifier() + "]");
+ }
+ if (mDeviceState == state.getIdentifier()) {
return;
}
- readPersistedSetting("updateDeviceState", state);
+ readPersistedSetting("updateDeviceState", state.getIdentifier());
} finally {
Trace.endSection();
}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 5882b56fff6a..572a6c12f3e1 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -113,7 +113,7 @@
android:excludeFromRecents="true"
/>
- <activity android:name="com.android.systemui.screenshot.ScrollViewActivity"
+ <activity android:name="com.android.systemui.screenshot.scroll.ScrollViewActivity"
android:exported="false" />
<activity android:name="com.android.systemui.screenshot.RecyclerViewActivity"
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
index 90587d7386ce..f1dfdf42ed0e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
@@ -20,16 +20,18 @@ import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
-import com.android.internal.jank.InteractionJankMonitor;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.power.data.repository.FakePowerRepository;
import com.android.systemui.power.domain.interactor.PowerInteractorFactory;
import com.android.systemui.res.R;
@@ -46,6 +48,7 @@ import org.mockito.MockitoAnnotations;
public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase {
+ private KosmosJavaAdapter mKosmos;
@Mock protected KeyguardStatusView mKeyguardStatusView;
@Mock protected KeyguardSliceViewController mKeyguardSliceViewController;
@@ -57,7 +60,6 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase {
@Mock protected ScreenOffAnimationController mScreenOffAnimationController;
@Mock protected KeyguardLogger mKeyguardLogger;
@Mock protected KeyguardStatusViewController mControllerMock;
- @Mock protected InteractionJankMonitor mInteractionJankMonitor;
@Mock protected ViewTreeObserver mViewTreeObserver;
@Mock protected DumpManager mDumpManager;
protected FakeKeyguardRepository mFakeKeyguardRepository;
@@ -71,6 +73,7 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase {
@Before
public void setup() {
+ mKosmos = new KosmosJavaAdapter(this);
MockitoAnnotations.initMocks(this);
KeyguardInteractorFactory.WithDependencies deps = KeyguardInteractorFactory.create();
@@ -87,7 +90,7 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase {
mDozeParameters,
mScreenOffAnimationController,
mKeyguardLogger,
- mInteractionJankMonitor,
+ mKosmos.getInteractionJankMonitor(),
deps.getKeyguardInteractor(),
mDumpManager,
PowerInteractorFactory.create(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 336a97ef09f4..fde45d34a4fd 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -135,6 +135,7 @@ import com.android.systemui.deviceentry.shared.model.ErrorFaceAuthenticationStat
import com.android.systemui.deviceentry.shared.model.FaceDetectionStatus;
import com.android.systemui.deviceentry.shared.model.FailedFaceAuthenticationStatus;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
@@ -195,7 +196,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
TEST_CARRIER_ID, PROFILE_CLASS_PROVISIONING);
private static final int FINGERPRINT_SENSOR_ID = 1;
-
+ private KosmosJavaAdapter mKosmos;
@Mock
private UserTracker mUserTracker;
@Mock
@@ -240,7 +241,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private AuthController mAuthController;
@Mock
private TelephonyListenerManager mTelephonyListenerManager;
- @Mock
private InteractionJankMonitor mInteractionJankMonitor;
@Mock
private LatencyTracker mLatencyTracker;
@@ -300,6 +300,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Before
public void setup() throws RemoteException {
+ mKosmos = new KosmosJavaAdapter(this);
+ mInteractionJankMonitor = mKosmos.getInteractionJankMonitor();
MockitoAnnotations.initMocks(this);
when(mSessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(mKeyguardInstanceId);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
index 96ce3abebeaf..b73e4e6ab015 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
@@ -18,6 +18,8 @@ import androidx.test.filters.SmallTest
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.policy.DecorView
import com.android.systemui.SysuiTestCase
+import com.android.systemui.jank.interactionJankMonitor
+import com.android.systemui.kosmos.Kosmos
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
@@ -31,7 +33,6 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@@ -43,7 +44,7 @@ class DialogTransitionAnimatorTest : SysuiTestCase() {
private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator
private val attachedViews = mutableSetOf<View>()
- @Mock lateinit var interactionJankMonitor: InteractionJankMonitor
+ val interactionJankMonitor = Kosmos().interactionJankMonitor
@get:Rule val rule = MockitoJUnit.rule()
@Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 416b33458cdd..072569d0e69b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -399,6 +399,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
@Ignore("b/302735104")
fun testShowCredentialUI_withCustomBp() {
+ mSetFlagsRule.disableFlags(FLAG_CONSTRAINT_BP)
val container = initializeFingerprintContainer(
authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
isUsingContentView = true
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
index 21b8aca363ca..c79cbab87576 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
@@ -85,7 +85,9 @@ class DeviceStateRepositoryTest : SysuiTestCase() {
testScope.runTest {
val state = displayState()
- deviceStateManagerListener.value.onStateChanged(TEST_FOLDED)
+ deviceStateManagerListener.value.onDeviceStateChanged(
+ getDeviceStateForIdentifier(TEST_FOLDED)
+ )
assertThat(state()).isEqualTo(DeviceState.FOLDED)
}
@@ -95,7 +97,9 @@ class DeviceStateRepositoryTest : SysuiTestCase() {
testScope.runTest {
val state = displayState()
- deviceStateManagerListener.value.onStateChanged(TEST_HALF_FOLDED)
+ deviceStateManagerListener.value.onDeviceStateChanged(
+ getDeviceStateForIdentifier(TEST_HALF_FOLDED)
+ )
assertThat(state()).isEqualTo(DeviceState.HALF_FOLDED)
}
@@ -105,7 +109,9 @@ class DeviceStateRepositoryTest : SysuiTestCase() {
testScope.runTest {
val state = displayState()
- deviceStateManagerListener.value.onStateChanged(TEST_UNFOLDED)
+ deviceStateManagerListener.value.onDeviceStateChanged(
+ getDeviceStateForIdentifier(TEST_UNFOLDED)
+ )
assertThat(state()).isEqualTo(DeviceState.UNFOLDED)
}
@@ -115,7 +121,9 @@ class DeviceStateRepositoryTest : SysuiTestCase() {
testScope.runTest {
val state = displayState()
- deviceStateManagerListener.value.onStateChanged(TEST_REAR_DISPLAY)
+ deviceStateManagerListener.value.onDeviceStateChanged(
+ getDeviceStateForIdentifier(TEST_REAR_DISPLAY)
+ )
assertThat(state()).isEqualTo(DeviceState.REAR_DISPLAY)
}
@@ -125,7 +133,9 @@ class DeviceStateRepositoryTest : SysuiTestCase() {
testScope.runTest {
val state = displayState()
- deviceStateManagerListener.value.onStateChanged(TEST_CONCURRENT_DISPLAY)
+ deviceStateManagerListener.value.onDeviceStateChanged(
+ getDeviceStateForIdentifier(TEST_CONCURRENT_DISPLAY)
+ )
assertThat(state()).isEqualTo(DeviceState.CONCURRENT_DISPLAY)
}
@@ -135,7 +145,9 @@ class DeviceStateRepositoryTest : SysuiTestCase() {
testScope.runTest {
val state = displayState()
- deviceStateManagerListener.value.onStateChanged(123456)
+ deviceStateManagerListener.value.onDeviceStateChanged(
+ getDeviceStateForIdentifier(123456)
+ )
assertThat(state()).isEqualTo(DeviceState.UNKNOWN)
}
@@ -152,6 +164,13 @@ class DeviceStateRepositoryTest : SysuiTestCase() {
private fun Int.toIntArray() = listOf(this).toIntArray()
+ private fun getDeviceStateForIdentifier(id: Int): android.hardware.devicestate.DeviceState {
+ return android.hardware.devicestate.DeviceState(
+ android.hardware.devicestate.DeviceState.Configuration.Builder(id, /* name= */ "")
+ .build()
+ )
+ }
+
private companion object {
// Used to fake the ids in the test. Note that there is no guarantees different devices will
// have the same ids (that's why the ones in this test start from 41)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 184924596341..272b48876a37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -75,7 +75,6 @@ import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.internal.foldables.FoldGracePeriodProvider;
-import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.widget.LockPatternUtils;
@@ -181,7 +180,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock NotificationShadeDepthController mNotificationShadeDepthController;
private @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private @Mock ScreenOffAnimationController mScreenOffAnimationController;
- private @Mock InteractionJankMonitor mInteractionJankMonitor;
private @Mock ScreenOnCoordinator mScreenOnCoordinator;
private @Mock KeyguardTransitions mKeyguardTransitions;
private @Mock ShadeController mShadeController;
@@ -235,8 +233,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
when(mPowerManager.isInteractive()).thenReturn(true);
- when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true);
- when(mInteractionJankMonitor.end(anyInt())).thenReturn(true);
mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
final ViewRootImpl testViewRoot = mock(ViewRootImpl.class);
when(testViewRoot.getView()).thenReturn(mock(View.class));
@@ -1245,7 +1241,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
() -> mNotificationShadeDepthController,
mScreenOnCoordinator,
mKeyguardTransitions,
- mInteractionJankMonitor,
+ mKosmos.getInteractionJankMonitor(),
mDreamOverlayStateController,
mJavaAdapter,
mWallpaperRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index a63b2211f71a..d1d9efc10ea7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -101,11 +101,12 @@ import android.text.TextUtils;
import androidx.preference.PreferenceManager;
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.people.PeopleBackupFollowUpJob;
import com.android.systemui.people.PeopleSpaceUtils;
import com.android.systemui.people.SharedPreferencesHelper;
+import com.android.systemui.res.R;
+import com.android.systemui.settings.FakeUserTracker;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import com.android.systemui.statusbar.SbnBuilder;
@@ -265,6 +266,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
private final FakeExecutor mFakeExecutor = new FakeExecutor(mClock);
+ private final FakeUserTracker mUserTracker = new FakeUserTracker();
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -272,7 +275,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
mManager = new PeopleSpaceWidgetManager(mContext, mAppWidgetManager, mIPeopleManager,
mPeopleManager, mLauncherApps, mNotifCollection, mPackageManager,
Optional.of(mBubbles), mUserManager, mBackupManager, mINotificationManager,
- mNotificationManager, mFakeExecutor);
+ mNotificationManager, mFakeExecutor, mUserTracker);
mManager.attach(mListenerService);
verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
@@ -1562,6 +1565,43 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS));
}
+ @Test
+ public void testUpdateGeneratedPreview_flagDisabled() {
+ mSetFlagsRule.disableFlags(android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS);
+ mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle());
+ verify(mAppWidgetManager, times(0)).setWidgetPreview(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateGeneratedPreview_userLocked() {
+ mSetFlagsRule.enableFlags(android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS);
+ when(mUserManager.isUserUnlocked(mUserTracker.getUserHandle())).thenReturn(false);
+
+ mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle());
+ verify(mAppWidgetManager, times(0)).setWidgetPreview(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateGeneratedPreview_userUnlocked() {
+ mSetFlagsRule.enableFlags(android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS);
+ when(mUserManager.isUserUnlocked(mUserTracker.getUserHandle())).thenReturn(true);
+ when(mAppWidgetManager.setWidgetPreview(any(), anyInt(), any())).thenReturn(true);
+
+ mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle());
+ verify(mAppWidgetManager, times(1)).setWidgetPreview(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateGeneratedPreview_doesNotSetTwice() {
+ mSetFlagsRule.enableFlags(android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS);
+ when(mUserManager.isUserUnlocked(mUserTracker.getUserHandle())).thenReturn(true);
+ when(mAppWidgetManager.setWidgetPreview(any(), anyInt(), any())).thenReturn(true);
+
+ mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle());
+ mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle());
+ verify(mAppWidgetManager, times(1)).setWidgetPreview(any(), anyInt(), any());
+ }
+
private void setFinalField(String fieldName, int value) {
try {
Field field = NotificationManager.Policy.class.getDeclaredField(fieldName);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java
index dc211303e52c..f88a5a0d9f41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java
@@ -19,7 +19,6 @@ package com.android.systemui.reardisplay;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotSame;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.reset;
@@ -28,6 +27,7 @@ import static org.mockito.Mockito.when;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -38,9 +38,7 @@ import android.widget.TextView;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.res.R;
import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.model.SysUiState;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.CommandQueue;
@@ -176,6 +174,6 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase {
DeviceStateManager.DeviceStateCallback {
@Override
- public void onStateChanged(int state) { }
+ public void onDeviceStateChanged(DeviceState state) { }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
index 4c8a4b0f8f61..aad461392cf6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import static com.google.common.util.concurrent.Futures.getUnchecked;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureClientTest.java
index 670a130d610a..10232602b655 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureClientTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import static org.junit.Assert.assertEquals;
@@ -37,8 +37,8 @@ import android.view.ScrollCaptureResponse;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
-import com.android.systemui.screenshot.ScrollCaptureClient.Session;
+import com.android.systemui.screenshot.scroll.ScrollCaptureClient.CaptureResult;
+import com.android.systemui.screenshot.scroll.ScrollCaptureClient.Session;
import com.google.common.util.concurrent.ListenableFuture;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
index 6f081c759df7..f39f5439d4ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import static com.google.common.util.concurrent.Futures.getUnchecked;
import static com.google.common.util.concurrent.Futures.immediateFuture;
@@ -36,7 +36,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.screenshot.ScrollCaptureClient.Session;
+import com.android.systemui.screenshot.scroll.ScrollCaptureClient.Session;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureFrameworkSmokeTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java
index de97bc36be56..5699cfc96c8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureFrameworkSmokeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java
index 4c84df2769a0..04aba1133a78 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollViewActivity.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import android.app.Activity;
import android.os.Bundle;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index 3ed8b28bd780..b9451bafec90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.shade;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -290,10 +289,6 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase {
when(mNotificationRemoteInputManager.isRemoteInputActive())
.thenReturn(false);
- when(mInteractionJankMonitor.begin(any(), anyInt()))
- .thenReturn(true);
- when(mInteractionJankMonitor.end(anyInt()))
- .thenReturn(true);
when(mPanelView.getParent()).thenReturn(mPanelViewParent);
when(mQs.getHeader()).thenReturn(mQsHeader);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index c8c54dbd4ac2..611cf91813ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -49,6 +49,7 @@ import android.app.WallpaperManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
@@ -1113,10 +1114,12 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
}
private void setDeviceState(int state) {
+ DeviceState deviceState = new DeviceState(
+ new DeviceState.Configuration.Builder(state, "TEST").build());
ArgumentCaptor<DeviceStateManager.DeviceStateCallback> callbackCaptor =
ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class);
verify(mDeviceStateManager).registerCallback(any(), callbackCaptor.capture());
- callbackCaptor.getValue().onStateChanged(state);
+ callbackCaptor.getValue().onDeviceStateChanged(deviceState);
}
private void setGoToSleepStates(int... states) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
index 649dc235f398..5d42d5167c27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.statusbar.phone
+import android.hardware.devicestate.DeviceState
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.internal.R
@@ -40,52 +41,52 @@ class FoldStateListenerTest : SysuiTestCase() {
@Before
fun setUp() {
initMocks(this)
- setFoldedStates(DEVICE_STATE_FOLDED)
- setGoToSleepStates(DEVICE_STATE_FOLDED)
+ setFoldedStates(DEVICE_STATE_FOLDED.identifier)
+ setGoToSleepStates(DEVICE_STATE_FOLDED.identifier)
sut = FoldStateListener(mContext, listener)
}
@Test
fun onStateChanged_stateFolded_notifiesWithFoldedAndGoingToSleep() {
- sut.onStateChanged(DEVICE_STATE_FOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_FOLDED)
verify(listener).onFoldStateChanged(FOLDED, WILL_GO_TO_SLEEP)
}
@Test
fun onStateChanged_stateHalfFolded_notifiesWithNotFoldedAndNotGoingToSleep() {
- sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_HALF_FOLDED)
verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
}
@Test
fun onStateChanged_stateUnfolded_notifiesWithNotFoldedAndNotGoingToSleep() {
- sut.onStateChanged(DEVICE_STATE_UNFOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_UNFOLDED)
verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
}
@Test
fun onStateChanged_stateUnfoldedThenHalfFolded_notifiesOnce() {
- sut.onStateChanged(DEVICE_STATE_UNFOLDED)
- sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_UNFOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_HALF_FOLDED)
verify(listener, times(1)).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
}
@Test
fun onStateChanged_stateHalfFoldedThenUnfolded_notifiesOnce() {
- sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
- sut.onStateChanged(DEVICE_STATE_UNFOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_HALF_FOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_UNFOLDED)
verify(listener, times(1)).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
}
@Test
fun onStateChanged_stateHalfFoldedThenFolded_notifiesTwice() {
- sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
- sut.onStateChanged(DEVICE_STATE_FOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_HALF_FOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_FOLDED)
val inOrder = Mockito.inOrder(listener)
inOrder.verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
@@ -94,8 +95,8 @@ class FoldStateListenerTest : SysuiTestCase() {
@Test
fun onStateChanged_stateFoldedThenHalfFolded_notifiesTwice() {
- sut.onStateChanged(DEVICE_STATE_FOLDED)
- sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_FOLDED)
+ sut.onDeviceStateChanged(DEVICE_STATE_HALF_FOLDED)
val inOrder = Mockito.inOrder(listener)
inOrder.verify(listener).onFoldStateChanged(FOLDED, WILL_GO_TO_SLEEP)
@@ -117,9 +118,18 @@ class FoldStateListenerTest : SysuiTestCase() {
}
companion object {
- private const val DEVICE_STATE_FOLDED = 123
- private const val DEVICE_STATE_HALF_FOLDED = 456
- private const val DEVICE_STATE_UNFOLDED = 789
+ private val DEVICE_STATE_FOLDED = DeviceState(
+ DeviceState.Configuration.Builder(123 /* id */, "FOLDED" /* name */)
+ .build()
+ )
+ private val DEVICE_STATE_HALF_FOLDED = DeviceState(
+ DeviceState.Configuration.Builder(456 /* id */, "HALF_FOLDED" /* name */)
+ .build()
+ )
+ private val DEVICE_STATE_UNFOLDED = DeviceState(
+ DeviceState.Configuration.Builder(789 /* id */, "UNFOLDED" /* name */)
+ .build()
+ )
private const val FOLDED = true
private const val NOT_FOLDED = false
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
index ce471705ed85..c606511456fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy
+import android.hardware.devicestate.DeviceState
import android.hardware.devicestate.DeviceStateManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -30,6 +31,7 @@ import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POST
import com.android.systemui.statusbar.policy.DevicePostureController.SUPPORTED_POSTURES_SIZE
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -72,6 +74,18 @@ class DevicePostureControllerImplTest : SysuiTestCase() {
com.android.internal.R.array.config_device_state_postures,
deviceStateToPostureMapping
)
+ whenever(deviceStateManager.supportedDeviceStates)
+ .thenReturn(
+ listOf(
+ DEVICE_STATE_CLOSED,
+ DEVICE_STATE_HALF_FOLDED,
+ DEVICE_STATE_OPENED,
+ DEVICE_STATE_FLIPPED,
+ DEVICE_STATE_UNKNOWN,
+ DEVICE_STATE_USE_BASE_STATE
+ )
+ )
+
underTest =
DevicePostureControllerImpl(
context,
@@ -86,20 +100,20 @@ class DevicePostureControllerImplTest : SysuiTestCase() {
var posture = -1
underTest.addCallback { posture = it }
- deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_UNKNOWN)
- assertThat(posture).isEqualTo(DEVICE_POSTURE_UNKNOWN)
-
- deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_CLOSED)
+ deviceStateCallback.value.onDeviceStateChanged(DEVICE_STATE_CLOSED)
assertThat(posture).isEqualTo(DEVICE_POSTURE_CLOSED)
- deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
+ deviceStateCallback.value.onDeviceStateChanged(DEVICE_STATE_HALF_FOLDED)
assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)
- deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_OPENED)
+ deviceStateCallback.value.onDeviceStateChanged(DEVICE_STATE_OPENED)
assertThat(posture).isEqualTo(DEVICE_POSTURE_OPENED)
- deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_FLIPPED)
+ deviceStateCallback.value.onDeviceStateChanged(DEVICE_STATE_FLIPPED)
assertThat(posture).isEqualTo(DEVICE_POSTURE_FLIPPED)
+
+ deviceStateCallback.value.onDeviceStateChanged(DEVICE_STATE_UNKNOWN)
+ assertThat(posture).isEqualTo(DEVICE_POSTURE_UNKNOWN)
}
@Test
@@ -107,15 +121,26 @@ class DevicePostureControllerImplTest : SysuiTestCase() {
var posture = -1
underTest.addCallback { posture = it }
- deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
+ deviceStateCallback.value.onDeviceStateChanged(DEVICE_STATE_HALF_FOLDED)
assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)
- // base state change doesn't change the posture
- deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_CLOSED)
+ val physicalProperties =
+ setOf(DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)
+ val updatedState =
+ DeviceState(
+ DeviceState.Configuration.Builder(
+ DEVICE_STATE_HALF_FOLDED.identifier,
+ DEVICE_STATE_HALF_FOLDED.name
+ )
+ .setPhysicalProperties(physicalProperties)
+ .build()
+ )
+ // state change with updated physical properties shouldn't cause a posture change
+ deviceStateCallback.value.onDeviceStateChanged(updatedState)
assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)
- // WHEN the display state maps to using the base state, then posture updates
- deviceStateCallback.value.onStateChanged(useBaseStateDeviceState)
+ // WHEN the display state maps to the physical state, then posture updates
+ deviceStateCallback.value.onDeviceStateChanged(DEVICE_STATE_USE_BASE_STATE)
assertThat(posture).isEqualTo(DEVICE_POSTURE_CLOSED)
}
@@ -124,20 +149,97 @@ class DevicePostureControllerImplTest : SysuiTestCase() {
var numPostureChanges = 0
underTest.addCallback { numPostureChanges++ }
- deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
+ deviceStateCallback.value.onDeviceStateChanged(DEVICE_STATE_HALF_FOLDED)
assertThat(numPostureChanges).isEqualTo(1)
- // base state changes doesn't send another posture update since the device state isn't
- // useBaseStateDeviceState
- deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_CLOSED)
- deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_HALF_OPENED)
- deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_FLIPPED)
- deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_OPENED)
- deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_UNKNOWN)
+ // update to physical properties doesn't send another posture update since the device state
+ // isn't useBaseStateDeviceState
+ deviceStateCallback.value.onDeviceStateChanged(
+ getStateUpdatedPhysicalProperties(DEVICE_STATE_HALF_FOLDED, DEVICE_STATE_CLOSED)
+ )
+ deviceStateCallback.value.onDeviceStateChanged(
+ getStateUpdatedPhysicalProperties(DEVICE_STATE_HALF_FOLDED, DEVICE_STATE_HALF_FOLDED)
+ )
+ deviceStateCallback.value.onDeviceStateChanged(
+ getStateUpdatedPhysicalProperties(DEVICE_STATE_HALF_FOLDED, DEVICE_STATE_OPENED)
+ )
+ deviceStateCallback.value.onDeviceStateChanged(
+ getStateUpdatedPhysicalProperties(DEVICE_STATE_HALF_FOLDED, DEVICE_STATE_UNKNOWN)
+ )
assertThat(numPostureChanges).isEqualTo(1)
}
private fun verifyRegistersForDeviceStateCallback() {
verify(deviceStateManager).registerCallback(eq(mainExecutor), deviceStateCallback.capture())
}
+
+ private fun getStateUpdatedPhysicalProperties(
+ currentState: DeviceState,
+ physicalState: DeviceState
+ ): DeviceState {
+ return DeviceState(
+ DeviceState.Configuration.Builder(currentState.identifier, currentState.name)
+ .setSystemProperties(currentState.configuration.systemProperties)
+ .setPhysicalProperties(physicalState.configuration.physicalProperties)
+ .build()
+ )
+ }
+
+ companion object {
+ val DEVICE_STATE_CLOSED =
+ DeviceState(
+ DeviceState.Configuration.Builder(
+ DEVICE_POSTURE_CLOSED /* id */,
+ "CLOSED" /* name */
+ )
+ .setPhysicalProperties(
+ setOf(DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)
+ )
+ .build()
+ )
+ val DEVICE_STATE_HALF_FOLDED =
+ DeviceState(
+ DeviceState.Configuration.Builder(
+ DEVICE_POSTURE_HALF_OPENED /* id */,
+ "HALF_FOLDED" /* name */
+ )
+ .setPhysicalProperties(
+ setOf(
+ DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN
+ )
+ )
+ .build()
+ )
+ val DEVICE_STATE_OPENED =
+ DeviceState(
+ DeviceState.Configuration.Builder(
+ DEVICE_POSTURE_OPENED /* id */,
+ "OPENED" /* name */
+ )
+ .setPhysicalProperties(
+ setOf(DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)
+ )
+ .build()
+ )
+ val DEVICE_STATE_FLIPPED =
+ DeviceState(
+ DeviceState.Configuration.Builder(
+ DEVICE_POSTURE_FLIPPED /* id */,
+ "FLIPPED" /* name */
+ )
+ .build()
+ )
+ val DEVICE_STATE_UNKNOWN =
+ DeviceState(
+ DeviceState.Configuration.Builder(
+ DEVICE_POSTURE_UNKNOWN /* id */,
+ "UNKNOWN" /* name */
+ )
+ .build()
+ )
+ val DEVICE_STATE_USE_BASE_STATE =
+ DeviceState(
+ DeviceState.Configuration.Builder(SUPPORTED_POSTURES_SIZE, "USE_BASE_STATE").build()
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index 4ccbd1b739f3..2955162f80c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.os.UserHandle;
import android.provider.Settings;
@@ -119,11 +120,11 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
mFakeRotationPolicy.setRotationLock(true);
- mDeviceStateCallback.onStateChanged(1);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(1));
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
// Settings only exist for state 0 and 1
- mDeviceStateCallback.onStateChanged(2);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2));
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
}
@@ -134,10 +135,10 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED, 1, DEVICE_STATE_ROTATION_LOCK_LOCKED);
mFakeRotationPolicy.setRotationLock(true);
- mDeviceStateCallback.onStateChanged(0);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0));
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
- mDeviceStateCallback.onStateChanged(1);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(1));
assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
}
@@ -147,7 +148,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
mFakeRotationPolicy.setRotationLock(true);
// State 2 -> Ignored -> Fall back to state 1 which is unlocked
- mDeviceStateCallback.onStateChanged(2);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2));
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
}
@@ -161,7 +162,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
mFakeRotationPolicy.setRotationLock(false);
// State 2 -> Ignored -> Fall back to state 1 which is locked
- mDeviceStateCallback.onStateChanged(2);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2));
assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
}
@@ -173,7 +174,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
mSettingsManager.onPersistedSettingsChanged();
mFakeRotationPolicy.setRotationLock(true);
- mDeviceStateCallback.onStateChanged(0);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0));
assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
@@ -189,10 +190,10 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
@Test
public void whenDeviceStateSwitchedToIgnoredState_useFallbackSetting() {
- mDeviceStateCallback.onStateChanged(0);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0));
assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
- mDeviceStateCallback.onStateChanged(2);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2));
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
}
@@ -202,10 +203,10 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
8, DEVICE_STATE_ROTATION_LOCK_IGNORED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
mFakeRotationPolicy.setRotationLock(true);
- mDeviceStateCallback.onStateChanged(1);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(1));
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
- mDeviceStateCallback.onStateChanged(8);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(8));
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
@@ -225,7 +226,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
0, DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
mFakeRotationPolicy.setRotationLock(false);
- mDeviceStateCallback.onStateChanged(0);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0));
assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
@@ -241,7 +242,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
initializeSettingsWith(
0, DEVICE_STATE_ROTATION_LOCK_LOCKED,
1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
- mDeviceStateCallback.onStateChanged(0);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(0));
mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
/* rotationLocked= */ false,
@@ -262,7 +263,7 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
0, DEVICE_STATE_ROTATION_LOCK_LOCKED,
1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
2, DEVICE_STATE_ROTATION_LOCK_IGNORED);
- mDeviceStateCallback.onStateChanged(2);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(2));
mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
/* rotationLocked= */ true,
@@ -283,8 +284,8 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
0, DEVICE_STATE_ROTATION_LOCK_LOCKED,
1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
8, DEVICE_STATE_ROTATION_LOCK_IGNORED);
- mDeviceStateCallback.onStateChanged(1);
- mDeviceStateCallback.onStateChanged(8);
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(1));
+ mDeviceStateCallback.onDeviceStateChanged(createDeviceStateForIdentifier(8));
mDeviceStateRotationLockSettingController.onRotationLockStateChanged(
/* rotationLocked= */ true,
@@ -320,6 +321,10 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase
mSettingsManager.onPersistedSettingsChanged();
}
+ private DeviceState createDeviceStateForIdentifier(int id) {
+ return new DeviceState(new DeviceState.Configuration.Builder(id, "" /* name */).build());
+ }
+
private static class FakeRotationPolicy implements RotationPolicyWrapper {
private boolean mRotationLock;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/jank/InteractionJankMonitorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/jank/InteractionJankMonitorKosmos.kt
index 5c5016daf029..e2b5869fce99 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/jank/InteractionJankMonitorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/jank/InteractionJankMonitorKosmos.kt
@@ -16,9 +16,24 @@
package com.android.systemui.jank
+import android.os.HandlerThread
import com.android.internal.jank.InteractionJankMonitor
+import com.android.internal.jank.InteractionJankMonitor.Configuration.Builder
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.spy
-val Kosmos.interactionJankMonitor by Fixture<InteractionJankMonitor> { mock() }
+val Kosmos.interactionJankMonitor by
+ Fixture<InteractionJankMonitor> {
+ spy(InteractionJankMonitor(HandlerThread("InteractionJankMonitor-Kosmos"))).apply {
+ doReturn(true).`when`(this).shouldMonitor()
+ doReturn(true).`when`(this).begin(any(), anyInt())
+ doReturn(true).`when`(this).begin(any<Builder>())
+ doReturn(true).`when`(this).end(anyInt())
+ doReturn(true).`when`(this).cancel(anyInt())
+ doReturn(true).`when`(this).cancel(anyInt(), anyInt())
+ }
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java b/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeScrollCaptureConnection.java
index 63f7c9755782..ea59c0a24cf8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeScrollCaptureConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/FakeSession.java b/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeSession.java
index 478658eb232d..3b7b158264cf 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/FakeSession.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.scroll;
import static android.util.MathUtils.constrain;
@@ -32,6 +32,8 @@ import android.hardware.HardwareBuffer;
import android.media.Image;
import android.util.Log;
+import com.android.systemui.screenshot.scroll.ScrollCaptureClient;
+
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 177c345686b9..e2ae3def0b1b 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -76,7 +76,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
@@ -397,11 +396,10 @@ public final class DeviceStateManagerService extends SystemService {
@NonNull
private DeviceStateInfo getDeviceStateInfoLocked() {
final List<DeviceState> supportedStates = getSupportedStatesLocked();
- final DeviceState baseState = mBaseState.orElse(null);
- final DeviceState currentState = mCommittedState.orElse(null);
+ final DeviceState baseState = mBaseState.orElse(INVALID_DEVICE_STATE);
+ final DeviceState currentState = mCommittedState.orElse(INVALID_DEVICE_STATE);
- return new DeviceStateInfo(supportedStates,
- baseState != null ? baseState : INVALID_DEVICE_STATE,
+ return new DeviceStateInfo(supportedStates, baseState,
createMergedDeviceState(currentState, baseState));
}
@@ -412,7 +410,7 @@ public final class DeviceStateManagerService extends SystemService {
*/
private DeviceState createMergedDeviceState(@Nullable DeviceState committedState,
@Nullable DeviceState baseState) {
- if (committedState == null) {
+ if (committedState.equals(INVALID_DEVICE_STATE)) {
return INVALID_DEVICE_STATE;
}
@@ -420,8 +418,7 @@ public final class DeviceStateManagerService extends SystemService {
committedState.getConfiguration().getSystemProperties();
Set<@DeviceState.DeviceStateProperties Integer> physicalProperties =
- baseState != null ? baseState.getConfiguration().getPhysicalProperties()
- : Collections.emptySet();
+ baseState.getConfiguration().getPhysicalProperties();
DeviceState.Configuration deviceStateConfiguration = new DeviceState.Configuration.Builder(
committedState.getIdentifier(), committedState.getName())
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 9b2dcc53f456..411666942b6d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -57,6 +57,9 @@ import com.android.server.display.config.DisplayQuirks;
import com.android.server.display.config.HbmTiming;
import com.android.server.display.config.HdrBrightnessData;
import com.android.server.display.config.HighBrightnessMode;
+import com.android.server.display.config.IdleScreenRefreshRateTimeout;
+import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
+import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholds;
import com.android.server.display.config.IntegerArray;
import com.android.server.display.config.LuxThrottling;
import com.android.server.display.config.NitsMap;
@@ -553,6 +556,18 @@ import javax.xml.datatype.DatatypeConfigurationException;
* <minorVersion>0</minorVersion>
* </usiVersion>
* <screenBrightnessCapForWearBedtimeMode>0.1</screenBrightnessCapForWearBedtimeMode>
+ * <idleScreenRefreshRateTimeout>
+ * <luxThresholds>
+ * <point>
+ * <lux>6</lux>
+ * <timeout>1000</timeout>
+ * </point>
+ * <point>
+ * <lux>10</lux>
+ * <timeout>800</timeout>
+ * </point>
+ * </luxThresholds>
+ * </idleScreenRefreshRateTimeout>
* </displayConfiguration>
* }
* </pre>
@@ -843,6 +858,14 @@ public class DisplayDeviceConfig {
private final Map<BrightnessLimitMapType, Map<Float, Float>>
mLuxThrottlingData = new HashMap<>();
+ /**
+ * The idle screen timeout configuration for switching to lower refresh rate
+ */
+ @NonNull
+ private List<IdleScreenRefreshRateTimeoutLuxThresholdPoint>
+ mIdleScreenRefreshRateTimeoutLuxThresholds = new ArrayList<>();
+
+
@Nullable
private HostUsiVersion mHostUsiVersion;
@@ -1999,6 +2022,7 @@ public class DisplayDeviceConfig {
loadUsiVersion(config);
mHdrBrightnessData = HdrBrightnessData.loadConfig(config);
loadBrightnessCapForWearBedtimeMode(config);
+ loadIdleScreenRefreshRateTimeoutConfigs(config);
} else {
Slog.w(TAG, "DisplayDeviceConfig file is null");
}
@@ -2024,6 +2048,7 @@ public class DisplayDeviceConfig {
loadAutoBrightnessAvailableFromConfigXml();
loadRefreshRateSetting(null);
loadBrightnessCapForWearBedtimeModeFromConfigXml();
+ loadIdleScreenRefreshRateTimeoutConfigs(null);
mLoadedFrom = "<config.xml>";
}
@@ -3326,6 +3351,47 @@ public class DisplayDeviceConfig {
}
}
+ private void loadIdleScreenRefreshRateTimeoutConfigs(@Nullable DisplayConfiguration config) {
+ if (mFlags.isIdleScreenRefreshRateTimeoutEnabled()
+ && config != null && config.getIdleScreenRefreshRateTimeout() != null) {
+ validateIdleScreenRefreshRateTimeoutConfig(
+ config.getIdleScreenRefreshRateTimeout());
+ mIdleScreenRefreshRateTimeoutLuxThresholds = config
+ .getIdleScreenRefreshRateTimeout().getLuxThresholds().getPoint();
+ }
+ }
+
+ private void validateIdleScreenRefreshRateTimeoutConfig(
+ IdleScreenRefreshRateTimeout idleScreenRefreshRateTimeoutConfig) {
+ IdleScreenRefreshRateTimeoutLuxThresholds idleScreenRefreshRateTimeoutLuxThresholds =
+ idleScreenRefreshRateTimeoutConfig.getLuxThresholds();
+
+ if (idleScreenRefreshRateTimeoutLuxThresholds != null) {
+ int previousLux = -1;
+ // Validate that the lux values are in the increasing order
+ for (IdleScreenRefreshRateTimeoutLuxThresholdPoint point :
+ idleScreenRefreshRateTimeoutLuxThresholds.getPoint()) {
+ int newLux = point.getLux().intValue();
+ if (previousLux >= newLux) {
+ throw new RuntimeException("Lux values should be in ascending order in the"
+ + " idle screen refresh rate timeout config");
+ }
+ previousLux = newLux;
+ }
+ }
+ }
+
+ /**
+ * Gets the idle screen refresh rate timeout(in ms) configuration list. For each entry, the lux
+ * value represent the lower bound of the lux range, and the value of the lux in the next
+ * point(INF if not present) represents the upper bound for the corresponding timeout(in ms)
+ */
+ @NonNull
+ public List<IdleScreenRefreshRateTimeoutLuxThresholdPoint>
+ getIdleScreenRefreshRateTimeoutLuxThresholdPoint() {
+ return mIdleScreenRefreshRateTimeoutLuxThresholds;
+ }
+
/**
* Extracts a float array from the specified {@link TypedArray}.
*
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ce7c22438d54..84eebe838954 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -22,6 +22,7 @@ import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;
import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_DISPLAYS;
+import static android.Manifest.permission.RESTRICT_DISPLAY_MODES;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
import static android.hardware.display.DisplayManager.EventsMask;
@@ -75,6 +76,7 @@ import android.graphics.Point;
import android.hardware.OverlayProperties;
import android.hardware.Sensor;
import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManagerInternal;
import android.hardware.display.AmbientBrightnessDayStats;
@@ -4530,6 +4532,14 @@ public final class DisplayManagerService extends SystemService {
disableConnectedDisplay_enforcePermission();
DisplayManagerService.this.enableConnectedDisplay(displayId, false);
}
+
+ @EnforcePermission(RESTRICT_DISPLAY_MODES)
+ @Override // Binder call
+ public void requestDisplayModes(IBinder token, int displayId, @Nullable int[] modeIds) {
+ requestDisplayModes_enforcePermission();
+ DisplayManagerService.this.mDisplayModeDirector.requestDisplayModes(
+ token, displayId, modeIds);
+ }
}
private static boolean isValidBrightness(float brightness) {
@@ -5034,30 +5044,22 @@ public final class DisplayManagerService extends SystemService {
* Listens to changes in device state and reports the state to LogicalDisplayMapper.
*/
class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
- // Base state corresponds to the physical state of the device
- private int mBaseState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
@Override
- public void onStateChanged(int deviceState) {
- boolean isDeviceStateOverrideActive = deviceState != mBaseState;
+ public void onDeviceStateChanged(DeviceState deviceState) {
synchronized (mSyncRoot) {
// Notify WindowManager that we are about to handle new device state, this should
// be sent before any work related to the device state in DisplayManager, so
// WindowManager could do implement that depends on the device state and display
// changes (serializes device state update and display change events)
Message msg = mHandler.obtainMessage(MSG_RECEIVED_DEVICE_STATE);
- msg.arg1 = deviceState;
+ msg.arg1 = deviceState.getIdentifier();
mHandler.sendMessage(msg);
mLogicalDisplayMapper
- .setDeviceStateLocked(deviceState, isDeviceStateOverrideActive);
+ .setDeviceStateLocked(deviceState.getIdentifier());
}
}
-
- @Override
- public void onBaseStateChanged(int state) {
- mBaseState = state;
- }
};
private class BrightnessPair {
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 21f90d4aeb94..f727eac71be8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -441,7 +441,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
mVirtualDeviceDisplayMapping.put(displayDevice.getUniqueId(), virtualDeviceUniqueId);
}
- void setDeviceStateLocked(int state, boolean isOverrideActive) {
+ void setDeviceStateLocked(int state) {
if (!mBootCompleted) {
// The boot animation might still be in progress, we do not want to switch states now
// as the boot animation would end up with an incorrect size.
@@ -465,7 +465,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState,
mInteractive, mBootCompleted);
final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState,
- isOverrideActive, mInteractive, mBootCompleted);
+ mInteractive, mBootCompleted);
// If all displays are off already, we can just transition here, unless we are trying to
// wake or sleep the device as part of this transition. In that case defer the final
@@ -513,8 +513,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
mBootCompleted = true;
if (mDeviceStateToBeAppliedAfterBoot
!= DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER) {
- setDeviceStateLocked(mDeviceStateToBeAppliedAfterBoot,
- /* isOverrideActive= */ false);
+ setDeviceStateLocked(mDeviceStateToBeAppliedAfterBoot);
}
}
}
@@ -560,7 +559,6 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
*
* @param pendingState device state we are moving to
* @param currentState device state we are currently in
- * @param isOverrideActive if a device state override is currently active or not
* @param isInteractive if the device is in an interactive state
* @param isBootCompleted is the device fully booted
*
@@ -568,13 +566,13 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
* @see #setDeviceStateLocked
*/
@VisibleForTesting
- boolean shouldDeviceBePutToSleep(int pendingState, int currentState, boolean isOverrideActive,
- boolean isInteractive, boolean isBootCompleted) {
+ boolean shouldDeviceBePutToSleep(int pendingState, int currentState, boolean isInteractive,
+ boolean isBootCompleted) {
return currentState != DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER
&& mDeviceStatesOnWhichToSleep.get(pendingState)
&& !mDeviceStatesOnWhichToSleep.get(currentState)
- && !isOverrideActive
- && isInteractive && isBootCompleted
+ && isInteractive
+ && isBootCompleted
&& !mFoldSettingProvider.shouldStayAwakeOnFold();
}
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 5f455db39dd4..e1a166ec95f5 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -92,9 +92,9 @@ public class DisplayManagerFlags {
Flags.FLAG_BRIGHTNESS_INT_RANGE_USER_PERCEPTION,
Flags::brightnessIntRangeUserPerception);
- private final FlagState mVsyncProximityVote = new FlagState(
- Flags.FLAG_ENABLE_EXTERNAL_VSYNC_PROXIMITY_VOTE,
- Flags::enableExternalVsyncProximityVote);
+ private final FlagState mRestrictDisplayModes = new FlagState(
+ Flags.FLAG_ENABLE_RESTRICT_DISPLAY_MODES,
+ Flags::enableRestrictDisplayModes);
private final FlagState mVsyncLowPowerVote = new FlagState(
Flags.FLAG_ENABLE_VSYNC_LOW_POWER_VOTE,
@@ -135,6 +135,11 @@ public class DisplayManagerFlags {
Flags::sensorBasedBrightnessThrottling
);
+ private final FlagState mIdleScreenRefreshRateTimeout = new FlagState(
+ Flags.FLAG_IDLE_SCREEN_REFRESH_RATE_TIMEOUT,
+ Flags::idleScreenRefreshRateTimeout
+ );
+
private final FlagState mRefactorDisplayPowerController = new FlagState(
Flags.FLAG_REFACTOR_DISPLAY_POWER_CONTROLLER,
@@ -237,8 +242,8 @@ public class DisplayManagerFlags {
return mBrightnessIntRangeUserPerceptionFlagState.isEnabled();
}
- public boolean isVsyncProximityVoteEnabled() {
- return mVsyncProximityVote.isEnabled();
+ public boolean isRestrictDisplayModesEnabled() {
+ return mRestrictDisplayModes.isEnabled();
}
public boolean isVsyncLowPowerVoteEnabled() {
@@ -280,6 +285,10 @@ public class DisplayManagerFlags {
return mSensorBasedBrightnessThrottling.isEnabled();
}
+ public boolean isIdleScreenRefreshRateTimeoutEnabled() {
+ return mIdleScreenRefreshRateTimeout.isEnabled();
+ }
+
public boolean isRefactorDisplayPowerControllerEnabled() {
return mRefactorDisplayPowerController.isEnabled();
}
@@ -302,7 +311,7 @@ public class DisplayManagerFlags {
pw.println(" " + mPowerThrottlingClamperFlagState);
pw.println(" " + mSmallAreaDetectionFlagState);
pw.println(" " + mBrightnessIntRangeUserPerceptionFlagState);
- pw.println(" " + mVsyncProximityVote);
+ pw.println(" " + mRestrictDisplayModes);
pw.println(" " + mBrightnessWearBedtimeModeClamperFlagState);
pw.println(" " + mAutoBrightnessModesFlagState);
pw.println(" " + mFastHdrTransitions);
@@ -310,6 +319,7 @@ public class DisplayManagerFlags {
pw.println(" " + mRefreshRateVotingTelemetry);
pw.println(" " + mPixelAnisotropyCorrectionEnabled);
pw.println(" " + mSensorBasedBrightnessThrottling);
+ pw.println(" " + mIdleScreenRefreshRateTimeout);
pw.println(" " + mRefactorDisplayPowerController);
}
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 d2909b898704..a5f241f4d68e 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
@@ -130,9 +130,9 @@ flag {
}
flag {
- name: "enable_external_vsync_proximity_vote"
+ name: "enable_restrict_display_modes"
namespace: "display_manager"
- description: "Feature flag for external vsync proximity vote"
+ description: "Feature flag for restriction display modes api"
bug: "284866750"
is_fixed_read_only: true
}
@@ -219,3 +219,11 @@ flag {
bug: "294444204"
is_fixed_read_only: true
}
+
+flag {
+ name: "idle_screen_refresh_rate_timeout"
+ namespace: "display_manager"
+ description: "Feature flag for reducing the refresh rate when the screen is idle after a timeout"
+ bug: "310026579"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/display/mode/BaseModeRefreshRateVote.java b/services/core/java/com/android/server/display/mode/BaseModeRefreshRateVote.java
index c53823139ffe..6d750c0aa3cb 100644
--- a/services/core/java/com/android/server/display/mode/BaseModeRefreshRateVote.java
+++ b/services/core/java/com/android/server/display/mode/BaseModeRefreshRateVote.java
@@ -16,6 +16,8 @@
package com.android.server.display.mode;
+import android.annotation.NonNull;
+
import java.util.Objects;
class BaseModeRefreshRateVote implements Vote {
@@ -31,7 +33,7 @@ class BaseModeRefreshRateVote implements Vote {
}
@Override
- public void updateSummary(VoteSummary summary) {
+ public void updateSummary(@NonNull VoteSummary summary) {
if (summary.appRequestBaseModeRefreshRate == 0f
&& mAppRequestBaseModeRefreshRate > 0f) {
summary.appRequestBaseModeRefreshRate = mAppRequestBaseModeRefreshRate;
diff --git a/services/core/java/com/android/server/display/mode/CombinedVote.java b/services/core/java/com/android/server/display/mode/CombinedVote.java
index 4b68791268e9..3cd16bf5c640 100644
--- a/services/core/java/com/android/server/display/mode/CombinedVote.java
+++ b/services/core/java/com/android/server/display/mode/CombinedVote.java
@@ -16,6 +16,8 @@
package com.android.server.display.mode;
+import android.annotation.NonNull;
+
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -28,7 +30,7 @@ class CombinedVote implements Vote {
}
@Override
- public void updateSummary(VoteSummary summary) {
+ public void updateSummary(@NonNull VoteSummary summary) {
mVotes.forEach(vote -> vote.updateSummary(summary));
}
diff --git a/services/core/java/com/android/server/display/mode/DisableRefreshRateSwitchingVote.java b/services/core/java/com/android/server/display/mode/DisableRefreshRateSwitchingVote.java
index 7f5740690c7f..7abb518ec494 100644
--- a/services/core/java/com/android/server/display/mode/DisableRefreshRateSwitchingVote.java
+++ b/services/core/java/com/android/server/display/mode/DisableRefreshRateSwitchingVote.java
@@ -16,6 +16,8 @@
package com.android.server.display.mode;
+import android.annotation.NonNull;
+
import java.util.Objects;
class DisableRefreshRateSwitchingVote implements Vote {
@@ -31,7 +33,7 @@ class DisableRefreshRateSwitchingVote implements Vote {
}
@Override
- public void updateSummary(VoteSummary summary) {
+ public void updateSummary(@NonNull VoteSummary summary) {
summary.disableRefreshRateSwitching =
summary.disableRefreshRateSwitching || mDisableRefreshRateSwitching;
}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 64cbd5488d90..495ae87fe0b9 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -41,6 +41,7 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
import android.net.Uri;
import android.os.Handler;
+import android.os.IBinder;
import android.os.IThermalEventListener;
import android.os.IThermalService;
import android.os.Looper;
@@ -80,7 +81,6 @@ import com.android.server.display.utils.AmbientFilterFactory;
import com.android.server.display.utils.DeviceConfigParsingUtils;
import com.android.server.display.utils.SensorUtils;
import com.android.server.sensors.SensorManagerInternal;
-import com.android.server.sensors.SensorManagerInternal.ProximityActiveListener;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.PrintWriter;
@@ -128,9 +128,12 @@ public class DisplayModeDirector {
private final SettingsObserver mSettingsObserver;
private final DisplayObserver mDisplayObserver;
private final UdfpsObserver mUdfpsObserver;
- private final SensorObserver mSensorObserver;
+ private final ProximitySensorObserver mSensorObserver;
private final HbmObserver mHbmObserver;
private final SkinThermalStatusObserver mSkinThermalStatusObserver;
+
+ @Nullable
+ private final SystemRequestObserver mSystemRequestObserver;
private final DeviceConfigParameterProvider mConfigParameterProvider;
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
@@ -203,6 +206,7 @@ public class DisplayModeDirector {
.isDisplaysRefreshRatesSynchronizationEnabled();
mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags
.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled();
+
mContext = context;
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
mInjector = injector;
@@ -222,10 +226,15 @@ public class DisplayModeDirector {
mVotesStorage = new VotesStorage(this::notifyDesiredDisplayModeSpecsChangedLocked,
mVotesStatsReporter);
mDisplayObserver = new DisplayObserver(context, handler, mVotesStorage);
- mSensorObserver = new SensorObserver(context, mVotesStorage, injector);
+ mSensorObserver = new ProximitySensorObserver(mVotesStorage, injector);
mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, mVotesStorage);
mHbmObserver = new HbmObserver(injector, mVotesStorage, BackgroundThread.getHandler(),
mDeviceConfigDisplaySettings);
+ if (mDvrrSupported && displayManagerFlags.isRestrictDisplayModesEnabled()) {
+ mSystemRequestObserver = new SystemRequestObserver(mVotesStorage);
+ } else {
+ mSystemRequestObserver = null;
+ }
mAlwaysRespectAppRequest = false;
mSupportsFrameRateOverride = injector.supportsFrameRateOverride();
}
@@ -520,6 +529,15 @@ public class DisplayModeDirector {
}
/**
+ * Delegates requestDisplayModes call to SystemRequestObserver
+ */
+ public void requestDisplayModes(IBinder token, int displayId, int[] modeIds) {
+ if (mSystemRequestObserver != null) {
+ mSystemRequestObserver.requestDisplayModes(token, displayId, modeIds);
+ }
+ }
+
+ /**
* Print the object's state and debug information into the given stream.
*
* @param pw The stream to dump information to.
@@ -970,10 +988,10 @@ public class DisplayModeDirector {
Settings.Global.LOW_POWER_MODE, 0 /*default*/) != 0;
final Vote vote;
if (inLowPowerMode && mVsynLowPowerVoteEnabled) {
- vote = Vote.forSupportedModes(List.of(
- new SupportedModesVote.SupportedMode(/* peakRefreshRate= */ 60f,
+ vote = Vote.forSupportedRefreshRates(List.of(
+ new SupportedRefreshRatesVote.RefreshRates(/* peakRefreshRate= */ 60f,
/* vsyncRate= */ 240f),
- new SupportedModesVote.SupportedMode(/* peakRefreshRate= */ 60f,
+ new SupportedRefreshRatesVote.RefreshRates(/* peakRefreshRate= */ 60f,
/* vsyncRate= */ 60f)
));
} else if (inLowPowerMode) {
@@ -2158,11 +2176,11 @@ public class DisplayModeDirector {
}
if (mVsyncLowLightBlockingVoteEnabled) {
- refreshRateSwitchingVote = Vote.forSupportedModesAndDisableRefreshRateSwitching(
+ refreshRateSwitchingVote = Vote.forSupportedRefreshRatesAndDisableSwitching(
List.of(
- new SupportedModesVote.SupportedMode(
+ new SupportedRefreshRatesVote.RefreshRates(
/* peakRefreshRate= */ 60f, /* vsyncRate= */ 60f),
- new SupportedModesVote.SupportedMode(
+ new SupportedRefreshRatesVote.RefreshRates(
/* peakRefreshRate= */120f, /* vsyncRate= */ 120f)));
} else {
refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching();
@@ -2498,116 +2516,6 @@ public class DisplayModeDirector {
}
}
- protected static final class SensorObserver implements ProximityActiveListener,
- DisplayManager.DisplayListener {
- private final String mProximitySensorName = null;
- private final String mProximitySensorType = Sensor.STRING_TYPE_PROXIMITY;
-
- private final VotesStorage mVotesStorage;
- private final Context mContext;
- private final Injector mInjector;
- @GuardedBy("mSensorObserverLock")
- private final SparseBooleanArray mDozeStateByDisplay = new SparseBooleanArray();
- private final Object mSensorObserverLock = new Object();
-
- private DisplayManager mDisplayManager;
- private DisplayManagerInternal mDisplayManagerInternal;
- @GuardedBy("mSensorObserverLock")
- private boolean mIsProxActive = false;
-
- SensorObserver(Context context, VotesStorage votesStorage, Injector injector) {
- mContext = context;
- mVotesStorage = votesStorage;
- mInjector = injector;
- }
-
- @Override
- public void onProximityActive(boolean isActive) {
- synchronized (mSensorObserverLock) {
- if (mIsProxActive != isActive) {
- mIsProxActive = isActive;
- recalculateVotesLocked();
- }
- }
- }
-
- public void observe() {
- mDisplayManager = mContext.getSystemService(DisplayManager.class);
- mDisplayManagerInternal = mInjector.getDisplayManagerInternal();
-
- final SensorManagerInternal sensorManager = mInjector.getSensorManagerInternal();
- sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
-
- synchronized (mSensorObserverLock) {
- for (Display d : mInjector.getDisplays()) {
- mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
- }
- }
- mInjector.registerDisplayListener(this, BackgroundThread.getHandler(),
- DisplayManager.EVENT_FLAG_DISPLAY_ADDED
- | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
- | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
- }
-
- private void recalculateVotesLocked() {
- final Display[] displays = mInjector.getDisplays();
- for (Display d : displays) {
- int displayId = d.getDisplayId();
- Vote vote = null;
- if (mIsProxActive && !mDozeStateByDisplay.get(displayId)) {
- final RefreshRateRange rate =
- mDisplayManagerInternal.getRefreshRateForDisplayAndSensor(
- displayId, mProximitySensorName, mProximitySensorType);
- if (rate != null) {
- vote = Vote.forPhysicalRefreshRates(rate.min, rate.max);
- }
- }
- mVotesStorage.updateVote(displayId, Vote.PRIORITY_PROXIMITY, vote);
- }
- }
-
- void dump(PrintWriter pw) {
- pw.println(" SensorObserver");
- synchronized (mSensorObserverLock) {
- pw.println(" mIsProxActive=" + mIsProxActive);
- pw.println(" mDozeStateByDisplay:");
- for (int i = 0; i < mDozeStateByDisplay.size(); i++) {
- final int id = mDozeStateByDisplay.keyAt(i);
- final boolean dozed = mDozeStateByDisplay.valueAt(i);
- pw.println(" " + id + " -> " + dozed);
- }
- }
- }
-
- @Override
- public void onDisplayAdded(int displayId) {
- boolean isDozeState = mInjector.isDozeState(mInjector.getDisplay(displayId));
- synchronized (mSensorObserverLock) {
- mDozeStateByDisplay.put(displayId, isDozeState);
- recalculateVotesLocked();
- }
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- boolean wasDozeState = mDozeStateByDisplay.get(displayId);
- synchronized (mSensorObserverLock) {
- mDozeStateByDisplay.put(displayId,
- mInjector.isDozeState(mInjector.getDisplay(displayId)));
- if (wasDozeState != mDozeStateByDisplay.get(displayId)) {
- recalculateVotesLocked();
- }
- }
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- synchronized (mSensorObserverLock) {
- mDozeStateByDisplay.delete(displayId);
- recalculateVotesLocked();
- }
- }
- }
/**
* Listens to DisplayManager for HBM status and applies any refresh-rate restrictions for
diff --git a/services/core/java/com/android/server/display/mode/ProximitySensorObserver.java b/services/core/java/com/android/server/display/mode/ProximitySensorObserver.java
new file mode 100644
index 000000000000..11418c147caa
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/ProximitySensorObserver.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import android.hardware.Sensor;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.util.SparseBooleanArray;
+import android.view.Display;
+import android.view.SurfaceControl;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.sensors.SensorManagerInternal;
+
+import java.io.PrintWriter;
+
+class ProximitySensorObserver implements
+ SensorManagerInternal.ProximityActiveListener,
+ DisplayManager.DisplayListener {
+ private final String mProximitySensorName = null;
+ private final String mProximitySensorType = Sensor.STRING_TYPE_PROXIMITY;
+
+ private final VotesStorage mVotesStorage;
+ private final DisplayModeDirector.Injector mInjector;
+ @GuardedBy("mSensorObserverLock")
+ private final SparseBooleanArray mDozeStateByDisplay = new SparseBooleanArray();
+ private final Object mSensorObserverLock = new Object();
+ private DisplayManagerInternal mDisplayManagerInternal;
+ @GuardedBy("mSensorObserverLock")
+ private boolean mIsProxActive = false;
+
+ ProximitySensorObserver(VotesStorage votesStorage, DisplayModeDirector.Injector injector) {
+ mVotesStorage = votesStorage;
+ mInjector = injector;
+ }
+
+ @Override
+ public void onProximityActive(boolean isActive) {
+ synchronized (mSensorObserverLock) {
+ if (mIsProxActive != isActive) {
+ mIsProxActive = isActive;
+ recalculateVotesLocked();
+ }
+ }
+ }
+
+ void observe() {
+ mDisplayManagerInternal = mInjector.getDisplayManagerInternal();
+
+ final SensorManagerInternal sensorManager = mInjector.getSensorManagerInternal();
+ sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
+
+ synchronized (mSensorObserverLock) {
+ for (Display d : mInjector.getDisplays()) {
+ mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
+ }
+ }
+ mInjector.registerDisplayListener(this, BackgroundThread.getHandler(),
+ DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+ | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
+ }
+
+ @GuardedBy("mSensorObserverLock")
+ private void recalculateVotesLocked() {
+ final Display[] displays = mInjector.getDisplays();
+ for (Display d : displays) {
+ int displayId = d.getDisplayId();
+ Vote vote = null;
+ if (mIsProxActive && !mDozeStateByDisplay.get(displayId)) {
+ final SurfaceControl.RefreshRateRange rate =
+ mDisplayManagerInternal.getRefreshRateForDisplayAndSensor(
+ displayId, mProximitySensorName, mProximitySensorType);
+ if (rate != null) {
+ vote = Vote.forPhysicalRefreshRates(rate.min, rate.max);
+ }
+ }
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_PROXIMITY, vote);
+ }
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println(" SensorObserver");
+ synchronized (mSensorObserverLock) {
+ pw.println(" mIsProxActive=" + mIsProxActive);
+ pw.println(" mDozeStateByDisplay:");
+ for (int i = 0; i < mDozeStateByDisplay.size(); i++) {
+ final int id = mDozeStateByDisplay.keyAt(i);
+ final boolean dozed = mDozeStateByDisplay.valueAt(i);
+ pw.println(" " + id + " -> " + dozed);
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ boolean isDozeState = mInjector.isDozeState(mInjector.getDisplay(displayId));
+ synchronized (mSensorObserverLock) {
+ mDozeStateByDisplay.put(displayId, isDozeState);
+ recalculateVotesLocked();
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ synchronized (mSensorObserverLock) {
+ boolean wasDozeState = mDozeStateByDisplay.get(displayId);
+ mDozeStateByDisplay.put(displayId,
+ mInjector.isDozeState(mInjector.getDisplay(displayId)));
+ if (wasDozeState != mDozeStateByDisplay.get(displayId)) {
+ recalculateVotesLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ synchronized (mSensorObserverLock) {
+ mDozeStateByDisplay.delete(displayId);
+ recalculateVotesLocked();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/RefreshRateVote.java b/services/core/java/com/android/server/display/mode/RefreshRateVote.java
index 670b8a13da4d..b96ab3b6be3d 100644
--- a/services/core/java/com/android/server/display/mode/RefreshRateVote.java
+++ b/services/core/java/com/android/server/display/mode/RefreshRateVote.java
@@ -16,6 +16,8 @@
package com.android.server.display.mode;
+import android.annotation.NonNull;
+
import java.util.Objects;
@@ -64,7 +66,7 @@ abstract class RefreshRateVote implements Vote {
* Vote: min(ignored) min(applied) min(applied+physical) max(applied) max(ignored)
*/
@Override
- public void updateSummary(VoteSummary summary) {
+ public void updateSummary(@NonNull VoteSummary summary) {
summary.minRenderFrameRate = Math.max(summary.minRenderFrameRate, mMinRefreshRate);
summary.maxRenderFrameRate = Math.min(summary.maxRenderFrameRate, mMaxRefreshRate);
// Physical refresh rate cannot be lower than the minimal render frame rate.
@@ -97,7 +99,7 @@ abstract class RefreshRateVote implements Vote {
* Vote: min(ignored) min(applied) max(applied+render) max(applied) max(ignored)
*/
@Override
- public void updateSummary(VoteSummary summary) {
+ public void updateSummary(@NonNull VoteSummary summary) {
summary.minPhysicalRefreshRate = Math.max(summary.minPhysicalRefreshRate,
mMinRefreshRate);
summary.maxPhysicalRefreshRate = Math.min(summary.maxPhysicalRefreshRate,
diff --git a/services/core/java/com/android/server/display/mode/SizeVote.java b/services/core/java/com/android/server/display/mode/SizeVote.java
index f2f8dc451098..f5a5abea9d9e 100644
--- a/services/core/java/com/android/server/display/mode/SizeVote.java
+++ b/services/core/java/com/android/server/display/mode/SizeVote.java
@@ -16,6 +16,8 @@
package com.android.server.display.mode;
+import android.annotation.NonNull;
+
import java.util.Objects;
class SizeVote implements Vote {
@@ -48,7 +50,7 @@ class SizeVote implements Vote {
}
@Override
- public void updateSummary(VoteSummary summary) {
+ public void updateSummary(@NonNull VoteSummary summary) {
if (mHeight > 0 && mWidth > 0) {
// For display size, disable refresh rate switching and base mode refresh rate use
// only the first vote we come across (i.e. the highest priority vote that includes
diff --git a/services/core/java/com/android/server/display/mode/SupportedModesVote.java b/services/core/java/com/android/server/display/mode/SupportedModesVote.java
index 7eebcc050b16..0cf8311128d0 100644
--- a/services/core/java/com/android/server/display/mode/SupportedModesVote.java
+++ b/services/core/java/com/android/server/display/mode/SupportedModesVote.java
@@ -16,77 +16,42 @@
package com.android.server.display.mode;
-import java.util.ArrayList;
+import android.annotation.NonNull;
+
import java.util.Collections;
import java.util.List;
import java.util.Objects;
-class SupportedModesVote implements Vote {
+public class SupportedModesVote implements Vote {
- final List<SupportedMode> mSupportedModes;
+ final List<Integer> mModeIds;
- SupportedModesVote(List<SupportedMode> supportedModes) {
- mSupportedModes = Collections.unmodifiableList(supportedModes);
+ SupportedModesVote(List<Integer> modeIds) {
+ mModeIds = Collections.unmodifiableList(modeIds);
}
-
- /**
- * Summary should have subset of supported modes.
- * If Vote1.supportedModes=(A,B), Vote2.supportedModes=(B,C) then summary.supportedModes=(B)
- * If summary.supportedModes==null then there is no restriction on supportedModes
- */
@Override
- public void updateSummary(VoteSummary summary) {
- if (summary.supportedModes == null) {
- summary.supportedModes = new ArrayList<>(mSupportedModes);
+ public void updateSummary(@NonNull VoteSummary summary) {
+ if (summary.supportedModeIds == null) {
+ summary.supportedModeIds = mModeIds;
} else {
- summary.supportedModes.retainAll(mSupportedModes);
+ summary.supportedModeIds.retainAll(mModeIds);
}
}
@Override
+ public String toString() {
+ return "SupportedModesVote{ mModeIds=" + mModeIds + " }";
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SupportedModesVote that)) return false;
- return mSupportedModes.equals(that.mSupportedModes);
+ return mModeIds.equals(that.mModeIds);
}
@Override
public int hashCode() {
- return Objects.hash(mSupportedModes);
- }
-
- @Override
- public String toString() {
- return "SupportedModesVote{ mSupportedModes=" + mSupportedModes + " }";
- }
-
- static class SupportedMode {
- final float mPeakRefreshRate;
- final float mVsyncRate;
-
-
- SupportedMode(float peakRefreshRate, float vsyncRate) {
- mPeakRefreshRate = peakRefreshRate;
- mVsyncRate = vsyncRate;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof SupportedMode that)) return false;
- return Float.compare(that.mPeakRefreshRate, mPeakRefreshRate) == 0
- && Float.compare(that.mVsyncRate, mVsyncRate) == 0;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mPeakRefreshRate, mVsyncRate);
- }
-
- @Override
- public String toString() {
- return "SupportedMode{ mPeakRefreshRate=" + mPeakRefreshRate
- + ", mVsyncRate=" + mVsyncRate + " }";
- }
+ return Objects.hash(mModeIds);
}
}
diff --git a/services/core/java/com/android/server/display/mode/SupportedRefreshRatesVote.java b/services/core/java/com/android/server/display/mode/SupportedRefreshRatesVote.java
new file mode 100644
index 000000000000..5305487b2ddd
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/SupportedRefreshRatesVote.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import android.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+class SupportedRefreshRatesVote implements Vote {
+
+ final List<RefreshRates> mRefreshRates;
+
+ SupportedRefreshRatesVote(List<RefreshRates> refreshRates) {
+ mRefreshRates = Collections.unmodifiableList(refreshRates);
+ }
+
+ /**
+ * Summary should have subset of supported modes.
+ * If Vote1.refreshRates=(A,B), Vote2.refreshRates=(B,C)
+ * then summary.supportedRefreshRates=(B)
+ * If summary.supportedRefreshRates==null then there is no restriction on supportedRefreshRates
+ */
+ @Override
+ public void updateSummary(@NonNull VoteSummary summary) {
+ if (summary.supportedRefreshRates == null) {
+ summary.supportedRefreshRates = new ArrayList<>(mRefreshRates);
+ } else {
+ summary.supportedRefreshRates.retainAll(mRefreshRates);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SupportedRefreshRatesVote that)) return false;
+ return mRefreshRates.equals(that.mRefreshRates);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRefreshRates);
+ }
+
+ @Override
+ public String toString() {
+ return "SupportedRefreshRatesVote{ mSupportedModes=" + mRefreshRates + " }";
+ }
+
+ static class RefreshRates {
+ final float mPeakRefreshRate;
+ final float mVsyncRate;
+
+ RefreshRates(float peakRefreshRate, float vsyncRate) {
+ mPeakRefreshRate = peakRefreshRate;
+ mVsyncRate = vsyncRate;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof RefreshRates that)) return false;
+ return Float.compare(that.mPeakRefreshRate, mPeakRefreshRate) == 0
+ && Float.compare(that.mVsyncRate, mVsyncRate) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPeakRefreshRate, mVsyncRate);
+ }
+
+ @Override
+ public String toString() {
+ return "RefreshRates{ mPeakRefreshRate=" + mPeakRefreshRate
+ + ", mVsyncRate=" + mVsyncRate + " }";
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/SystemRequestObserver.java b/services/core/java/com/android/server/display/mode/SystemRequestObserver.java
new file mode 100644
index 000000000000..15f19cca99db
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/SystemRequestObserver.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * SystemRequestObserver responsible for handling system requests to filter allowable display
+ * modes
+ */
+class SystemRequestObserver {
+ private final VotesStorage mVotesStorage;
+
+ private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ // noop, binderDied(@NonNull IBinder who) is overridden
+ }
+ @Override
+ public void binderDied(@NonNull IBinder who) {
+ removeSystemRequestedVotes(who);
+ who.unlinkToDeath(mDeathRecipient, 0);
+ }
+ };
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final Map<IBinder, SparseArray<List<Integer>>> mDisplaysRestrictions = new HashMap<>();
+
+ SystemRequestObserver(VotesStorage storage) {
+ mVotesStorage = storage;
+ }
+
+ void requestDisplayModes(IBinder token, int displayId, @Nullable int[] modeIds) {
+ if (modeIds == null) {
+ removeSystemRequestedVote(token, displayId);
+ } else {
+ addSystemRequestedVote(token, displayId, modeIds);
+ }
+ }
+
+ private void addSystemRequestedVote(IBinder token, int displayId, @NonNull int[] modeIds) {
+ try {
+ boolean needLinkToDeath = false;
+ List<Integer> modeIdsList = new ArrayList<>();
+ for (int mode: modeIds) {
+ modeIdsList.add(mode);
+ }
+ synchronized (mLock) {
+ SparseArray<List<Integer>> modesByDisplay = mDisplaysRestrictions.get(token);
+ if (modesByDisplay == null) {
+ needLinkToDeath = true;
+ modesByDisplay = new SparseArray<>();
+ mDisplaysRestrictions.put(token, modesByDisplay);
+ }
+
+ modesByDisplay.put(displayId, modeIdsList);
+ updateStorageLocked(displayId);
+ }
+ if (needLinkToDeath) {
+ token.linkToDeath(mDeathRecipient, 0);
+ }
+ } catch (RemoteException re) {
+ removeSystemRequestedVotes(token);
+ }
+ }
+
+ private void removeSystemRequestedVote(IBinder token, int displayId) {
+ boolean needToUnlink = false;
+ synchronized (mLock) {
+ SparseArray<List<Integer>> modesByDisplay = mDisplaysRestrictions.get(token);
+ if (modesByDisplay != null) {
+ modesByDisplay.remove(displayId);
+ needToUnlink = modesByDisplay.size() == 0;
+ updateStorageLocked(displayId);
+ }
+ }
+ if (needToUnlink) {
+ token.unlinkToDeath(mDeathRecipient, 0);
+ }
+ }
+
+ private void removeSystemRequestedVotes(IBinder token) {
+ synchronized (mLock) {
+ SparseArray<List<Integer>> removed = mDisplaysRestrictions.remove(token);
+ if (removed != null) {
+ for (int i = 0; i < removed.size(); i++) {
+ updateStorageLocked(removed.keyAt(i));
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void updateStorageLocked(int displayId) {
+ List<Integer> modeIds = new ArrayList<>();
+ boolean[] modesFound = new boolean[1];
+
+ mDisplaysRestrictions.forEach((key, value) -> {
+ List<Integer> modesForDisplay = value.get(displayId);
+ if (modesForDisplay != null) {
+ if (!modesFound[0]) {
+ modeIds.addAll(modesForDisplay);
+ modesFound[0] = true;
+ } else {
+ modeIds.retainAll(modesForDisplay);
+ }
+ }
+ });
+
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_SYSTEM_REQUESTED_MODES,
+ modesFound[0] ? Vote.forSupportedModes(modeIds) : null);
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java
index e8d5a194f8f4..5b987f491a45 100644
--- a/services/core/java/com/android/server/display/mode/Vote.java
+++ b/services/core/java/com/android/server/display/mode/Vote.java
@@ -16,6 +16,8 @@
package com.android.server.display.mode;
+import android.annotation.NonNull;
+
import java.util.List;
interface Vote {
@@ -91,26 +93,29 @@ interface Vote {
// For concurrent displays we want to limit refresh rate on all displays
int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 12;
+ // For internal application to limit display modes to specific ids
+ int PRIORITY_SYSTEM_REQUESTED_MODES = 13;
+
// LOW_POWER_MODE force the render frame rate to [0, 60HZ] if
// Settings.Global.LOW_POWER_MODE is on.
- int PRIORITY_LOW_POWER_MODE = 13;
+ int PRIORITY_LOW_POWER_MODE = 14;
// PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
// higher priority voters' result is a range, it will fix the rate to a single choice.
// It's used to avoid refresh rate switches in certain conditions which may result in the
// user seeing the display flickering when the switches occur.
- int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 14;
+ int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 15;
// Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
- int PRIORITY_SKIN_TEMPERATURE = 15;
+ int PRIORITY_SKIN_TEMPERATURE = 16;
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
// set to a high priority.
- int PRIORITY_PROXIMITY = 16;
+ int PRIORITY_PROXIMITY = 17;
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
// to function, so this needs to be the highest priority of all votes.
- int PRIORITY_UDFPS = 17;
+ int PRIORITY_UDFPS = 18;
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -128,7 +133,7 @@ interface Vote {
*/
int INVALID_SIZE = -1;
- void updateSummary(VoteSummary summary);
+ void updateSummary(@NonNull VoteSummary summary);
static Vote forPhysicalRefreshRates(float minRefreshRate, float maxRefreshRate) {
return new CombinedVote(
@@ -166,15 +171,22 @@ interface Vote {
return new BaseModeRefreshRateVote(baseModeRefreshRate);
}
- static Vote forSupportedModes(List<SupportedModesVote.SupportedMode> supportedModes) {
- return new SupportedModesVote(supportedModes);
+ static Vote forSupportedRefreshRates(
+ List<SupportedRefreshRatesVote.RefreshRates> refreshRates) {
+ return new SupportedRefreshRatesVote(refreshRates);
}
+ static Vote forSupportedModes(List<Integer> modeIds) {
+ return new SupportedModesVote(modeIds);
+ }
+
+
- static Vote forSupportedModesAndDisableRefreshRateSwitching(
- List<SupportedModesVote.SupportedMode> supportedModes) {
+ static Vote forSupportedRefreshRatesAndDisableSwitching(
+ List<SupportedRefreshRatesVote.RefreshRates> supportedRefreshRates) {
return new CombinedVote(
- List.of(forDisableRefreshRateSwitching(), forSupportedModes(supportedModes)));
+ List.of(forDisableRefreshRateSwitching(),
+ forSupportedRefreshRates(supportedRefreshRates)));
}
static String priorityToString(int priority) {
diff --git a/services/core/java/com/android/server/display/mode/VoteSummary.java b/services/core/java/com/android/server/display/mode/VoteSummary.java
index 5fc36b589d38..d4ce892eeba9 100644
--- a/services/core/java/com/android/server/display/mode/VoteSummary.java
+++ b/services/core/java/com/android/server/display/mode/VoteSummary.java
@@ -16,6 +16,7 @@
package com.android.server.display.mode;
+import android.annotation.Nullable;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -39,7 +40,11 @@ final class VoteSummary {
public boolean disableRefreshRateSwitching;
public float appRequestBaseModeRefreshRate;
- public List<SupportedModesVote.SupportedMode> supportedModes;
+ @Nullable
+ public List<SupportedRefreshRatesVote.RefreshRates> supportedRefreshRates;
+
+ @Nullable
+ public List<Integer> supportedModeIds;
final boolean mIsDisplayResolutionRangeVotingEnabled;
@@ -112,6 +117,9 @@ final class VoteSummary {
boolean missingBaseModeRefreshRate = appRequestBaseModeRefreshRate > 0f;
for (Display.Mode mode : modes) {
+ if (!validateRefreshRatesSupported(mode)) {
+ continue;
+ }
if (!validateModeSupported(mode)) {
continue;
}
@@ -253,21 +261,37 @@ final class VoteSummary {
}
private boolean validateModeSupported(Display.Mode mode) {
- if (supportedModes == null || !mSupportedModesVoteEnabled) {
+ if (supportedModeIds == null || !mSupportedModesVoteEnabled) {
+ return true;
+ }
+ if (supportedModeIds.contains(mode.getModeId())) {
return true;
}
- for (SupportedModesVote.SupportedMode supportedMode : supportedModes) {
- if (equalsWithinFloatTolerance(mode.getRefreshRate(), supportedMode.mPeakRefreshRate)
- && equalsWithinFloatTolerance(mode.getVsyncRate(), supportedMode.mVsyncRate)) {
+ if (mLoggingEnabled) {
+ Slog.w(TAG, "Discarding mode " + mode.getModeId()
+ + ", supportedMode not found"
+ + ": mode.modeId=" + mode.getModeId()
+ + ", supportedModeIds=" + supportedModeIds);
+ }
+ return false;
+ }
+
+ private boolean validateRefreshRatesSupported(Display.Mode mode) {
+ if (supportedRefreshRates == null || !mSupportedModesVoteEnabled) {
+ return true;
+ }
+ for (SupportedRefreshRatesVote.RefreshRates refreshRates : this.supportedRefreshRates) {
+ if (equalsWithinFloatTolerance(mode.getRefreshRate(), refreshRates.mPeakRefreshRate)
+ && equalsWithinFloatTolerance(mode.getVsyncRate(), refreshRates.mVsyncRate)) {
return true;
}
}
if (mLoggingEnabled) {
Slog.w(TAG, "Discarding mode " + mode.getModeId()
- + ", supportedMode not found"
+ + ", supportedRefreshRates not found"
+ ": mode.refreshRate=" + mode.getRefreshRate()
+ ", mode.vsyncRate=" + mode.getVsyncRate()
- + ", supportedModes=" + supportedModes);
+ + ", supportedRefreshRates=" + supportedRefreshRates);
}
return false;
}
@@ -298,7 +322,8 @@ final class VoteSummary {
return false;
}
- if (supportedModes != null && mSupportedModesVoteEnabled && supportedModes.isEmpty()) {
+ if (supportedRefreshRates != null && mSupportedModesVoteEnabled
+ && supportedRefreshRates.isEmpty()) {
if (mLoggingEnabled) {
Slog.w(TAG, "Vote summary resulted in empty set (empty supportedModes)");
}
@@ -345,7 +370,8 @@ final class VoteSummary {
minHeight = 0;
disableRefreshRateSwitching = false;
appRequestBaseModeRefreshRate = 0f;
- supportedModes = null;
+ supportedRefreshRates = null;
+ supportedModeIds = null;
if (mLoggingEnabled) {
Slog.i(TAG, "Summary reset: " + this);
}
@@ -367,7 +393,8 @@ final class VoteSummary {
+ ", minHeight=" + minHeight
+ ", disableRefreshRateSwitching=" + disableRefreshRateSwitching
+ ", appRequestBaseModeRefreshRate=" + appRequestBaseModeRefreshRate
- + ", supportedModes=" + supportedModes
+ + ", supportedRefreshRates=" + supportedRefreshRates
+ + ", supportedModeIds=" + supportedModeIds
+ ", mIsDisplayResolutionRangeVotingEnabled="
+ mIsDisplayResolutionRangeVotingEnabled
+ ", mSupportedModesVoteEnabled=" + mSupportedModesVoteEnabled
diff --git a/services/core/java/com/android/server/display/mode/VotesStatsReporter.java b/services/core/java/com/android/server/display/mode/VotesStatsReporter.java
index e80b9451dd14..7562a525b5f6 100644
--- a/services/core/java/com/android/server/display/mode/VotesStatsReporter.java
+++ b/services/core/java/com/android/server/display/mode/VotesStatsReporter.java
@@ -117,11 +117,11 @@ class VotesStatsReporter {
maxRefreshRate = (int) physicalVote.mMaxRefreshRate;
} else if (!ignoreRenderRate && (vote instanceof RefreshRateVote.RenderVote renderVote)) {
maxRefreshRate = (int) renderVote.mMaxRefreshRate;
- } else if (vote instanceof SupportedModesVote supportedModesVote) {
- // SupportedModesVote limits mode by specific refreshRates, so highest rr is allowed
+ } else if (vote instanceof SupportedRefreshRatesVote refreshRatesVote) {
+ // SupportedRefreshRatesVote limits mode by refreshRates, so highest rr is allowed
maxRefreshRate = 0;
- for (SupportedModesVote.SupportedMode mode : supportedModesVote.mSupportedModes) {
- maxRefreshRate = Math.max(maxRefreshRate, (int) mode.mPeakRefreshRate);
+ for (SupportedRefreshRatesVote.RefreshRates rr : refreshRatesVote.mRefreshRates) {
+ maxRefreshRate = Math.max(maxRefreshRate, (int) rr.mPeakRefreshRate);
}
} else if (vote instanceof CombinedVote combinedVote) {
for (Vote subVote: combinedVote.mVotes) {
diff --git a/services/core/java/com/android/server/display/mode/VotesStorage.java b/services/core/java/com/android/server/display/mode/VotesStorage.java
index 56c7c18c0a11..6becf1c46d05 100644
--- a/services/core/java/com/android/server/display/mode/VotesStorage.java
+++ b/services/core/java/com/android/server/display/mode/VotesStorage.java
@@ -18,6 +18,7 @@ package com.android.server.display.mode;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -124,6 +125,44 @@ class VotesStorage {
}
}
+ /** removes all votes with certain priority from vote storage */
+ void removeAllVotesForPriority(int priority) {
+ if (mLoggingEnabled) {
+ Slog.i(TAG, "removeAllVotesForPriority(priority="
+ + Vote.priorityToString(priority) + ")");
+ }
+ if (priority < Vote.MIN_PRIORITY || priority > Vote.MAX_PRIORITY) {
+ Slog.w(TAG, "Received an invalid priority, ignoring:"
+ + " priority=" + Vote.priorityToString(priority));
+ return;
+ }
+ IntArray removedVotesDisplayIds = new IntArray();
+ synchronized (mStorageLock) {
+ int size = mVotesByDisplay.size();
+ for (int i = 0; i < size; i++) {
+ SparseArray<Vote> votes = mVotesByDisplay.valueAt(i);
+ if (votes.get(priority) != null) {
+ votes.remove(priority);
+ removedVotesDisplayIds.add(mVotesByDisplay.keyAt(i));
+ }
+ }
+ }
+ if (mLoggingEnabled) {
+ Slog.i(TAG, "Removed votes with priority=" + priority
+ + " for displays=" + removedVotesDisplayIds);
+ }
+ int removedVotesSize = removedVotesDisplayIds.size();
+ if (removedVotesSize > 0) {
+ if (mVotesStatsReporter != null) {
+ for (int i = 0; i < removedVotesSize; i++) {
+ mVotesStatsReporter.reportVoteChanged(
+ removedVotesDisplayIds.get(i), priority, null);
+ }
+ }
+ mListener.onChanged();
+ }
+ }
+
/** dump class values, for debugging */
void dump(@NonNull PrintWriter pw) {
SparseArray<SparseArray<Vote>> votesByDisplayLocal = new SparseArray<>();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index b50e2bf317b5..6ff8cf3cc2c8 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -56,6 +56,7 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.DisplayManagerInternal;
@@ -7152,9 +7153,10 @@ public final class PowerManagerService extends SystemService
private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
@Override
- public void onStateChanged(int deviceState) {
- if (mDeviceState != deviceState) {
- mDeviceState = deviceState;
+ public void onDeviceStateChanged(@NonNull DeviceState deviceState) {
+ int stateIdentifier = deviceState.getIdentifier();
+ if (mDeviceState != stateIdentifier) {
+ mDeviceState = stateIdentifier;
// Device-state interactions are applied to the default display so that they
// are reflected only with the default power group.
userActivityInternal(Display.DEFAULT_DISPLAY, mClock.uptimeMillis(),
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6fa6957f2949..04e298810dad 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -328,6 +328,7 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.service.contentcapture.ActivityEvent;
@@ -1003,6 +1004,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Whether the Activity allows state sharing in untrusted embedding
private final boolean mAllowUntrustedEmbeddingStateSharing;
+ // TODO(b/329378309): Remove this once the overview handles the configuration correctly.
+ private static final boolean OVERRIDE_OVERVIEW_CONFIGURATION =
+ SystemProperties.getBoolean("persist.wm.debug.override_overview_configuration", true);
+
// Records whether client has overridden the WindowAnimation_(Open/Close)(Enter/Exit)Animation.
private CustomAppTransition mCustomOpenTransition;
private CustomAppTransition mCustomCloseTransition;
@@ -8608,7 +8613,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming()) {
rotation = mDisplayContent.getRotation();
}
- if (!mWmService.mFlags.mInsetsDecoupledConfiguration
+ final int activityType = inOutConfig.windowConfiguration.getActivityType();
+ if (OVERRIDE_OVERVIEW_CONFIGURATION
+ && (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS)) {
+ // Do not early return and provide the override. This should be removed shortly as we
+ // don't override 1P components.
+ } else if (!mWmService.mFlags.mInsetsDecoupledConfiguration
|| info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED)
|| getCompatDisplayInsets() != null
|| isFloating(parentWindowingMode) || fullBounds == null
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 46bac161f0a6..2b337aed5b87 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5700,7 +5700,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// window becomes visible while the sync group is still active.
return true;
}
- if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mLastConfigReportedToClient && isDrawn()) {
+ if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mLastConfigReportedToClient && isDrawn()
+ && mPrepareSyncSeqId <= 0) {
// Complete the sync state immediately for a drawn window that doesn't need to redraw.
onSyncFinishedDrawing();
}
diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
index 0a9ce2fed7fc..9dc70afad9d9 100644
--- a/services/core/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp
@@ -108,18 +108,6 @@ static jboolean android_server_UsbDeviceManager_isStartRequested(JNIEnv* /* env
return (result == 1);
}
-static jint android_server_UsbDeviceManager_getAudioMode(JNIEnv* /* env */, jobject /* thiz */)
-{
- int fd = open(DRIVER_NAME, O_RDWR);
- if (fd < 0) {
- ALOGE("could not open %s", DRIVER_NAME);
- return false;
- }
- int result = ioctl(fd, ACCESSORY_GET_AUDIO_MODE);
- close(fd);
- return result;
-}
-
static jobject android_server_UsbDeviceManager_openControl(JNIEnv *env, jobject /* thiz */, jstring jFunction) {
ScopedUtfChars function(env, jFunction);
bool ptp = false;
@@ -148,16 +136,13 @@ static jobject android_server_UsbDeviceManager_openControl(JNIEnv *env, jobject
}
static const JNINativeMethod method_table[] = {
- { "nativeGetAccessoryStrings", "()[Ljava/lang/String;",
- (void*)android_server_UsbDeviceManager_getAccessoryStrings },
- { "nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;",
- (void*)android_server_UsbDeviceManager_openAccessory },
- { "nativeIsStartRequested", "()Z",
- (void*)android_server_UsbDeviceManager_isStartRequested },
- { "nativeGetAudioMode", "()I",
- (void*)android_server_UsbDeviceManager_getAudioMode },
- { "nativeOpenControl", "(Ljava/lang/String;)Ljava/io/FileDescriptor;",
- (void*)android_server_UsbDeviceManager_openControl },
+ {"nativeGetAccessoryStrings", "()[Ljava/lang/String;",
+ (void *)android_server_UsbDeviceManager_getAccessoryStrings},
+ {"nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;",
+ (void *)android_server_UsbDeviceManager_openAccessory},
+ {"nativeIsStartRequested", "()Z", (void *)android_server_UsbDeviceManager_isStartRequested},
+ {"nativeOpenControl", "(Ljava/lang/String;)Ljava/io/FileDescriptor;",
+ (void *)android_server_UsbDeviceManager_openControl},
};
int register_android_server_UsbDeviceManager(JNIEnv *env)
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index b38a2f9558e9..d0df2b20721b 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -168,6 +168,10 @@
<xs:element type="nonNegativeDecimal" name="screenBrightnessCapForWearBedtimeMode">
<xs:annotation name="final"/>
</xs:element>
+ <!-- Timeout after which we reduce the refresh rate if the screen has been idle, in order to save power. -->
+ <xs:element type="idleScreenRefreshRateTimeout" name="idleScreenRefreshRateTimeout" minOccurs="0">
+ <xs:annotation name="final"/>
+ </xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
@@ -772,6 +776,30 @@
</xs:sequence>
</xs:complexType>
+ <xs:complexType name="idleScreenRefreshRateTimeout">
+ <xs:element name="luxThresholds" type="idleScreenRefreshRateTimeoutLuxThresholds" minOccurs="0">
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:complexType>
+
+ <!-- Lux based timeout after which we reduce the refresh rate if the screen has been idle, in order to save power. -->
+ <xs:complexType name="idleScreenRefreshRateTimeoutLuxThresholds">
+ <xs:sequence>
+ <xs:element name="point" type="idleScreenRefreshRateTimeoutLuxThresholdPoint" maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:complexType>
+
+ <!-- Represents a tuple of lux and timeout(in ms), which represents the timeout value for the lux in
+ the [luxValue, nextLuxValue (INF if missing)) -->
+ <xs:complexType name="idleScreenRefreshRateTimeoutLuxThresholdPoint">
+ <xs:element name="lux" type="xs:nonNegativeInteger">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element name="timeout" type="xs:nonNegativeInteger">
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:complexType>
+
<!-- Predefined type names as defined by
AutomaticBrightnessController.AutomaticBrightnessMode -->
<xs:simpleType name="AutoBrightnessModeName">
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index b329db4a2076..00dc90828d90 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -111,6 +111,7 @@ package com.android.server.display.config {
method public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholdsIdle();
method @Nullable public final com.android.server.display.config.HdrBrightnessConfig getHdrBrightnessConfig();
method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode();
+ method public final com.android.server.display.config.IdleScreenRefreshRateTimeout getIdleScreenRefreshRateTimeout();
method public final com.android.server.display.config.SensorDetails getLightSensor();
method public com.android.server.display.config.LuxThrottling getLuxThrottling();
method @Nullable public final String getName();
@@ -146,6 +147,7 @@ package com.android.server.display.config {
method public final void setDisplayBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds);
method public final void setHdrBrightnessConfig(@Nullable com.android.server.display.config.HdrBrightnessConfig);
method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
+ method public final void setIdleScreenRefreshRateTimeout(com.android.server.display.config.IdleScreenRefreshRateTimeout);
method public final void setLightSensor(com.android.server.display.config.SensorDetails);
method public void setLuxThrottling(com.android.server.display.config.LuxThrottling);
method public final void setName(@Nullable String);
@@ -222,6 +224,25 @@ package com.android.server.display.config {
method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal);
}
+ public class IdleScreenRefreshRateTimeout {
+ ctor public IdleScreenRefreshRateTimeout();
+ method public final com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholds getLuxThresholds();
+ method public final void setLuxThresholds(com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholds);
+ }
+
+ public class IdleScreenRefreshRateTimeoutLuxThresholdPoint {
+ ctor public IdleScreenRefreshRateTimeoutLuxThresholdPoint();
+ method public final java.math.BigInteger getLux();
+ method public final java.math.BigInteger getTimeout();
+ method public final void setLux(java.math.BigInteger);
+ method public final void setTimeout(java.math.BigInteger);
+ }
+
+ public class IdleScreenRefreshRateTimeoutLuxThresholds {
+ ctor public IdleScreenRefreshRateTimeoutLuxThresholds();
+ method public java.util.List<com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint> getPoint();
+ }
+
public class IntegerArray {
ctor public IntegerArray();
method public java.util.List<java.math.BigInteger> getItem();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 2867041511b5..35b69f812ff0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -54,6 +54,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.server.display.config.HdrBrightnessData;
+import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
import com.android.server.display.config.ThermalStatus;
import com.android.server.display.feature.DisplayManagerFlags;
@@ -108,6 +109,7 @@ public final class DisplayDeviceConfigTest {
when(mContext.getResources()).thenReturn(mResources);
when(mFlags.areAutoBrightnessModesEnabled()).thenReturn(true);
when(mFlags.isSensorBasedBrightnessThrottlingEnabled()).thenReturn(true);
+ when(mFlags.isIdleScreenRefreshRateTimeoutEnabled()).thenReturn(true);
mockDeviceConfigs();
}
@@ -146,6 +148,8 @@ public final class DisplayDeviceConfigTest {
assertNull(mDisplayDeviceConfig.getProximitySensor().type);
assertNull(mDisplayDeviceConfig.getProximitySensor().name);
assertEquals(TEMPERATURE_TYPE_SKIN, mDisplayDeviceConfig.getTempSensor().type);
+ assertEquals(List.of(), mDisplayDeviceConfig
+ .getIdleScreenRefreshRateTimeoutLuxThresholdPoint());
assertNull(mDisplayDeviceConfig.getTempSensor().name);
assertTrue(mDisplayDeviceConfig.isAutoBrightnessAvailable());
}
@@ -226,6 +230,19 @@ public final class DisplayDeviceConfigTest {
assertNotNull(mDisplayDeviceConfig.getHostUsiVersion());
assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMajorVersion(), 2);
assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMinorVersion(), 0);
+
+ List<IdleScreenRefreshRateTimeoutLuxThresholdPoint>
+ idleScreenRefreshRateTimeoutLuxThresholdPoints =
+ mDisplayDeviceConfig.getIdleScreenRefreshRateTimeoutLuxThresholdPoint();
+ assertEquals(2, idleScreenRefreshRateTimeoutLuxThresholdPoints.size());
+ assertEquals(6, idleScreenRefreshRateTimeoutLuxThresholdPoints.get(0).getLux()
+ .intValue());
+ assertEquals(1000, idleScreenRefreshRateTimeoutLuxThresholdPoints.get(0)
+ .getTimeout().intValue());
+ assertEquals(10, idleScreenRefreshRateTimeoutLuxThresholdPoints.get(1)
+ .getLux().intValue());
+ assertEquals(800, idleScreenRefreshRateTimeoutLuxThresholdPoints.get(1)
+ .getTimeout().intValue());
}
@Test
@@ -734,6 +751,8 @@ public final class DisplayDeviceConfigTest {
assertEquals(brightnessIntToFloat(35),
mDisplayDeviceConfig.getBrightnessCapForWearBedtimeMode(), ZERO_DELTA);
+ assertEquals(List.of(), mDisplayDeviceConfig
+ .getIdleScreenRefreshRateTimeoutLuxThresholdPoint());
}
@Test
@@ -1587,6 +1606,18 @@ public final class DisplayDeviceConfigTest {
+ "<screenBrightnessCapForWearBedtimeMode>"
+ "0.1"
+ "</screenBrightnessCapForWearBedtimeMode>"
+ + "<idleScreenRefreshRateTimeout>"
+ + "<luxThresholds>"
+ + "<point>"
+ + "<lux>6</lux>"
+ + "<timeout>1000</timeout>"
+ + "</point>"
+ + "<point>"
+ + "<lux>10</lux>"
+ + "<timeout>800</timeout>"
+ + "</point>"
+ + "</luxThresholds>"
+ + "</idleScreenRefreshRateTimeout>"
+ "</displayConfiguration>\n";
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 48fc4078999d..869cec8d733d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -78,6 +78,7 @@ import android.graphics.Insets;
import android.graphics.Rect;
import android.hardware.Sensor;
import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceState;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.Curve;
@@ -721,7 +722,9 @@ public class DisplayManagerServiceTest {
IDisplayManagerCallback displayChangesCallback = registerDisplayChangeCallback(
displayManager);
- listener.onStateChanged(123);
+ listener.onDeviceStateChanged(new DeviceState(
+ new DeviceState.Configuration.Builder(123 /* identifier */,
+ "TEST" /* name */).build()));
waitForIdleHandler(handler);
InOrder inOrder = inOrder(mMockWindowManagerInternal, displayChangesCallback);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 2939192d3d2e..d0c7077f29c0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -650,7 +650,6 @@ public class LogicalDisplayMapperTest {
public void testDeviceShouldBePutToSleep() {
assertTrue(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
DEVICE_STATE_OPEN,
- /* isOverrideActive= */false,
/* isInteractive= */true,
/* isBootCompleted= */true));
}
@@ -661,7 +660,6 @@ public class LogicalDisplayMapperTest {
assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
DEVICE_STATE_OPEN,
- /* isOverrideActive= */false,
/* isInteractive= */true,
/* isBootCompleted= */true));
}
@@ -670,21 +668,10 @@ public class LogicalDisplayMapperTest {
public void testDeviceShouldNotBePutToSleep() {
assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_OPEN,
DEVICE_STATE_CLOSED,
- /* isOverrideActive= */false,
/* isInteractive= */true,
/* isBootCompleted= */true));
assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
INVALID_DEVICE_STATE_IDENTIFIER,
- /* isOverrideActive= */false,
- /* isInteractive= */true,
- /* isBootCompleted= */true));
- }
-
- @Test
- public void testDeviceShouldNotBePutToSleepDifferentBaseState() {
- assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
- DEVICE_STATE_OPEN,
- /* isOverrideActive= */true,
/* isInteractive= */true,
/* isBootCompleted= */true));
}
@@ -750,7 +737,7 @@ public class LogicalDisplayMapperTest {
// We can only have one default display
assertEquals(DEFAULT_DISPLAY, id(display1));
- mLogicalDisplayMapper.setDeviceStateLocked(0, false);
+ mLogicalDisplayMapper.setDeviceStateLocked(0);
advanceTime(1000);
// The new state is not applied until the boot is completed
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
@@ -771,7 +758,7 @@ public class LogicalDisplayMapperTest {
assertEquals("concurrent", mLogicalDisplayMapper.getDisplayLocked(device2)
.getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
- mLogicalDisplayMapper.setDeviceStateLocked(1, false);
+ mLogicalDisplayMapper.setDeviceStateLocked(1);
advanceTime(1000);
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
@@ -784,7 +771,7 @@ public class LogicalDisplayMapperTest {
mLogicalDisplayMapper.getDisplayLocked(device2)
.getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
- mLogicalDisplayMapper.setDeviceStateLocked(2, false);
+ mLogicalDisplayMapper.setDeviceStateLocked(2);
advanceTime(1000);
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
@@ -861,7 +848,7 @@ public class LogicalDisplayMapperTest {
// 3) Send DISPLAY_DEVICE_EVENT_CHANGE to inform the mapper of the new display state
// 4) Dispatch handler events.
mLogicalDisplayMapper.onBootCompleted();
- mLogicalDisplayMapper.setDeviceStateLocked(0, false);
+ mLogicalDisplayMapper.setDeviceStateLocked(0);
mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
advanceTime(1000);
final int[] allDisplayIds = mLogicalDisplayMapper.getDisplayIdsLocked(
@@ -891,7 +878,7 @@ public class LogicalDisplayMapperTest {
/* includeDisabled= */ false));
// Now do it again to go back to state 1
- mLogicalDisplayMapper.setDeviceStateLocked(1, false);
+ mLogicalDisplayMapper.setDeviceStateLocked(1);
mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
advanceTime(1000);
final int[] threeDisplaysEnabled = mLogicalDisplayMapper.getDisplayIdsLocked(
@@ -945,7 +932,7 @@ public class LogicalDisplayMapperTest {
// We can only have one default display
assertEquals(DEFAULT_DISPLAY, id(display1));
- mLogicalDisplayMapper.setDeviceStateLocked(0, false);
+ mLogicalDisplayMapper.setDeviceStateLocked(0);
advanceTime(1000);
mLogicalDisplayMapper.onBootCompleted();
advanceTime(1000);
@@ -964,11 +951,11 @@ public class LogicalDisplayMapperTest {
/////////////////
private void finishBootAndFoldDevice() {
- mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_OPEN, false);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_OPEN);
advanceTime(1000);
mLogicalDisplayMapper.onBootCompleted();
advanceTime(1000);
- mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED, false);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED);
advanceTime(1000);
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt
index 638924eeb2a3..b182ccef091e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt
@@ -95,9 +95,9 @@ class BrightnessObserverTest {
) {
ALL_ENABLED(true, true, CombinedVote(
listOf(DisableRefreshRateSwitchingVote(true),
- SupportedModesVote(
- listOf(SupportedModesVote.SupportedMode(60f, 60f),
- SupportedModesVote.SupportedMode(120f, 120f)))))),
+ SupportedRefreshRatesVote(
+ listOf(SupportedRefreshRatesVote.RefreshRates(60f, 60f),
+ SupportedRefreshRatesVote.RefreshRates(120f, 120f)))))),
VRR_NOT_SUPPORTED(false, true, DisableRefreshRateSwitchingVote(true)),
VSYNC_VOTE_DISABLED(true, false, DisableRefreshRateSwitchingVote(true))
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/ProximitySensorObserverTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/ProximitySensorObserverTest.java
new file mode 100644
index 000000000000..e93e5bc63dd8
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/ProximitySensorObserverTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.sensors.SensorManagerInternal;
+
+import junitparams.JUnitParamsRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(JUnitParamsRunner.class)
+public class ProximitySensorObserverTest {
+
+ private static final float FLOAT_TOLERANCE = 0.01f;
+ private static final int DISPLAY_ID = 1;
+ private static final SurfaceControl.RefreshRateRange REFRESH_RATE_RANGE =
+ new SurfaceControl.RefreshRateRange(60, 90);
+
+ private final VotesStorage mStorage = new VotesStorage(() -> { }, null);
+ private final FakesInjector mInjector = new FakesInjector();
+ private ProximitySensorObserver mSensorObserver;
+
+ @Mock
+ DisplayManagerInternal mMockDisplayManagerInternal;
+ @Mock
+ SensorManagerInternal mMockSensorManagerInternal;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mMockDisplayManagerInternal.getRefreshRateForDisplayAndSensor(eq(DISPLAY_ID),
+ any(), any())).thenReturn(REFRESH_RATE_RANGE);
+ mSensorObserver = new ProximitySensorObserver(mStorage, mInjector);
+ mSensorObserver.observe();
+ }
+
+ @Test
+ public void testAddsProximityVoteIfSensorManagerProximityActive() {
+ mSensorObserver.onProximityActive(true);
+
+ SparseArray<Vote> displayVotes = mStorage.getVotes(DISPLAY_ID);
+ assertThat(displayVotes.size()).isEqualTo(1);
+ Vote vote = displayVotes.get(Vote.PRIORITY_PROXIMITY);
+ assertThat(vote).isNotNull();
+ assertThat(vote).isInstanceOf(CombinedVote.class);
+ CombinedVote combinedVote = (CombinedVote) vote;
+ RefreshRateVote.PhysicalVote physicalVote =
+ (RefreshRateVote.PhysicalVote) combinedVote.mVotes.get(0);
+ assertThat(physicalVote.mMinRefreshRate).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(physicalVote.mMaxRefreshRate).isWithin(FLOAT_TOLERANCE).of(90);
+ }
+
+ @Test
+ public void testDoesNotAddProximityVoteIfSensorManagerProximityNotActive() {
+ mSensorObserver.onProximityActive(false);
+
+ SparseArray<Vote> displayVotes = mStorage.getVotes(DISPLAY_ID);
+ assertThat(displayVotes.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void testDoesNotAddProximityVoteIfDoze() {
+ mInjector.mDozeState = true;
+ mSensorObserver.onDisplayChanged(DISPLAY_ID);
+ mSensorObserver.onProximityActive(true);
+
+ SparseArray<Vote> displayVotes = mStorage.getVotes(DISPLAY_ID);
+ assertThat(displayVotes.size()).isEqualTo(0);
+ }
+
+ private class FakesInjector extends DisplayModeDirectorTest.FakesInjector {
+
+ private boolean mDozeState = false;
+
+ @Override
+ public Display[] getDisplays() {
+ return new Display[] { createDisplay(DISPLAY_ID) };
+ }
+
+ @Override
+ public DisplayManagerInternal getDisplayManagerInternal() {
+ return mMockDisplayManagerInternal;
+ }
+
+ @Override
+ public SensorManagerInternal getSensorManagerInternal() {
+ return mMockSensorManagerInternal;
+ }
+
+ @Override
+ public boolean isDozeState(Display d) {
+ return mDozeState;
+ }
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
index ebb4f1889cd6..230317ba738b 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt
@@ -85,9 +85,9 @@ class SettingsObserverTest {
internal val expectedVote: Vote?
) {
ALL_ENABLED(true, true, true,
- SupportedModesVote(listOf(
- SupportedModesVote.SupportedMode(60f, 240f),
- SupportedModesVote.SupportedMode(60f, 60f)
+ SupportedRefreshRatesVote(listOf(
+ SupportedRefreshRatesVote.RefreshRates(60f, 240f),
+ SupportedRefreshRatesVote.RefreshRates(60f, 60f)
))),
LOW_POWER_OFF(true, true, false, null),
DVRR_NOT_SUPPORTED_LOW_POWER_ON(false, true, true,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedModesVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedModesVoteTest.kt
index 04e626536eba..6ce49b8cb31e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedModesVoteTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedModesVoteTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,12 +27,9 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class SupportedModesVoteTest {
- private val supportedModes = listOf(
- SupportedModesVote.SupportedMode(60f, 90f ),
- SupportedModesVote.SupportedMode(120f, 240f )
- )
+ private val supportedModes = listOf(1, 2, 4)
- private val otherMode = SupportedModesVote.SupportedMode(120f, 120f )
+ private val otherMode = 5
private lateinit var supportedModesVote: SupportedModesVote
@@ -42,31 +39,31 @@ class SupportedModesVoteTest {
}
@Test
- fun `adds supported modes if supportedModes in summary is null`() {
+ fun `adds supported mode ids if supportedModeIds in summary is null`() {
val summary = createVotesSummary()
supportedModesVote.updateSummary(summary)
- assertThat(summary.supportedModes).containsExactlyElementsIn(supportedModes)
+ assertThat(summary.supportedModeIds).containsExactlyElementsIn(supportedModes)
}
@Test
- fun `does not add supported modes if summary has empty list of modes`() {
+ fun `does not add supported mode ids if summary has empty list of modeIds`() {
val summary = createVotesSummary()
- summary.supportedModes = ArrayList()
+ summary.supportedModeIds = ArrayList()
supportedModesVote.updateSummary(summary)
- assertThat(summary.supportedModes).isEmpty()
+ assertThat(summary.supportedModeIds).isEmpty()
}
@Test
fun `filters out modes that does not match vote`() {
val summary = createVotesSummary()
- summary.supportedModes = ArrayList(listOf(otherMode, supportedModes[0]))
+ summary.supportedModeIds = ArrayList(listOf(otherMode, supportedModes[0]))
supportedModesVote.updateSummary(summary)
- assertThat(summary.supportedModes).containsExactly(supportedModes[0])
+ assertThat(summary.supportedModeIds).containsExactly(supportedModes[0])
}
} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedRefreshRatesVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedRefreshRatesVoteTest.kt
new file mode 100644
index 000000000000..d0c112be24a2
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SupportedRefreshRatesVoteTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SupportedRefreshRatesVoteTest {
+ private val refreshRates = listOf(
+ SupportedRefreshRatesVote.RefreshRates(60f, 90f),
+ SupportedRefreshRatesVote.RefreshRates(120f, 240f)
+ )
+
+ private val otherMode = SupportedRefreshRatesVote.RefreshRates(120f, 120f)
+
+ private lateinit var supportedRefreshRatesVote: SupportedRefreshRatesVote
+
+ @Before
+ fun setUp() {
+ supportedRefreshRatesVote = SupportedRefreshRatesVote(refreshRates)
+ }
+
+ @Test
+ fun `adds supported refresh rates if supportedModes in summary is null`() {
+ val summary = createVotesSummary()
+
+ supportedRefreshRatesVote.updateSummary(summary)
+
+ assertThat(summary.supportedRefreshRates).containsExactlyElementsIn(refreshRates)
+ }
+
+ @Test
+ fun `does not add supported refresh rates if summary has empty list of refresh rates`() {
+ val summary = createVotesSummary()
+ summary.supportedRefreshRates = ArrayList()
+
+ supportedRefreshRatesVote.updateSummary(summary)
+
+ assertThat(summary.supportedRefreshRates).isEmpty()
+ }
+
+ @Test
+ fun `filters out supported refresh rates that does not match vote`() {
+ val summary = createVotesSummary()
+ summary.supportedRefreshRates = ArrayList(listOf(otherMode, refreshRates[0]))
+
+ supportedRefreshRatesVote.updateSummary(summary)
+
+ assertThat(summary.supportedRefreshRates).containsExactly(refreshRates[0])
+ }
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt
new file mode 100644
index 000000000000..c49205bcfe3d
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode
+
+import android.os.IBinder
+import android.os.RemoteException
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doThrow
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+private const val DISPLAY_ID = 1
+private const val DISPLAY_ID_OTHER = 2
+
+@SmallTest
+@RunWith(TestParameterInjector::class)
+class SystemRequestObserverTest {
+
+
+ @get:Rule
+ val mockitoRule = MockitoJUnit.rule()
+
+ private val mockToken = mock<IBinder>()
+ private val mockOtherToken = mock<IBinder>()
+
+ private val storage = VotesStorage({}, null)
+
+ @Test
+ fun `requestDisplayModes adds vote to storage`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+
+ val votes = storage.getVotes(DISPLAY_ID)
+ assertThat(votes.size()).isEqualTo(1)
+ val vote = votes.get(Vote.PRIORITY_SYSTEM_REQUESTED_MODES)
+ assertThat(vote).isInstanceOf(SupportedModesVote::class.java)
+ val supportedModesVote = vote as SupportedModesVote
+ assertThat(supportedModesVote.mModeIds.size).isEqualTo(requestedModes.size)
+ for (mode in requestedModes) {
+ assertThat(supportedModesVote.mModeIds).contains(mode)
+ }
+ }
+
+ @Test
+ fun `requestDisplayModes overrides votes in storage`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, intArrayOf(1, 2, 3))
+
+ val overrideModes = intArrayOf(10, 20, 30)
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, overrideModes)
+
+ val votes = storage.getVotes(DISPLAY_ID)
+ assertThat(votes.size()).isEqualTo(1)
+ val vote = votes.get(Vote.PRIORITY_SYSTEM_REQUESTED_MODES)
+ assertThat(vote).isInstanceOf(SupportedModesVote::class.java)
+ val supportedModesVote = vote as SupportedModesVote
+ assertThat(supportedModesVote.mModeIds.size).isEqualTo(overrideModes.size)
+ for (mode in overrideModes) {
+ assertThat(supportedModesVote.mModeIds).contains(mode)
+ }
+ }
+
+ @Test
+ fun `requestDisplayModes removes vote to storage`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null)
+
+ val votes = storage.getVotes(DISPLAY_ID)
+ assertThat(votes.size()).isEqualTo(0)
+ }
+
+ @Test
+ fun `requestDisplayModes calls linkToDeath to token`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+
+ verify(mockToken).linkToDeath(any(), eq(0))
+ }
+
+ @Test
+ fun `does not add votes to storage if binder died when requestDisplayModes called`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+
+ doThrow(RemoteException()).whenever(mockOtherToken).linkToDeath(any(), eq(0))
+ systemRequestObserver.requestDisplayModes(mockOtherToken, DISPLAY_ID, requestedModes)
+
+ val votes = storage.getVotes(DISPLAY_ID)
+ assertThat(votes.size()).isEqualTo(0)
+ }
+
+ @Test
+ fun `removes all votes from storage when binder dies`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+ val deathRecipientCaptor = argumentCaptor<IBinder.DeathRecipient>()
+ verify(mockToken).linkToDeath(deathRecipientCaptor.capture(), eq(0))
+
+ deathRecipientCaptor.lastValue.binderDied(mockToken)
+
+ val votes = storage.getVotes(DISPLAY_ID)
+ assertThat(votes.size()).isEqualTo(0)
+ }
+
+ @Test
+ fun `calls unlinkToDeath on token when no votes remaining`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null)
+
+ verify(mockToken).unlinkToDeath(any(), eq(0))
+ }
+
+ @Test
+ fun `does not call unlinkToDeath on token when votes for other display in storage`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID_OTHER, requestedModes)
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null)
+
+ verify(mockToken, never()).unlinkToDeath(any(), eq(0))
+ }
+
+ @Test
+ fun `requestDisplayModes subset modes from different tokens`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+
+ val requestedOtherModes = intArrayOf(2, 3, 4)
+ systemRequestObserver.requestDisplayModes(mockOtherToken, DISPLAY_ID, requestedOtherModes)
+
+ verify(mockToken).linkToDeath(any(), eq(0))
+ verify(mockOtherToken).linkToDeath(any(), eq(0))
+ verify(mockToken, never()).unlinkToDeath(any(), eq(0))
+ verify(mockOtherToken, never()).unlinkToDeath(any(), eq(0))
+
+ val expectedModes = intArrayOf(2, 3)
+ val votes = storage.getVotes(DISPLAY_ID)
+ assertThat(votes.size()).isEqualTo(1)
+ val vote = votes.get(Vote.PRIORITY_SYSTEM_REQUESTED_MODES)
+ assertThat(vote).isInstanceOf(SupportedModesVote::class.java)
+ val supportedModesVote = vote as SupportedModesVote
+ assertThat(supportedModesVote.mModeIds.size).isEqualTo(expectedModes.size)
+ for (mode in expectedModes) {
+ assertThat(supportedModesVote.mModeIds).contains(mode)
+ }
+ }
+
+ @Test
+ fun `recalculates vote if one binder dies`() {
+ val systemRequestObserver = SystemRequestObserver(storage)
+ val requestedModes = intArrayOf(1, 2, 3)
+ systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+
+ val requestedOtherModes = intArrayOf(2, 3, 4)
+ systemRequestObserver.requestDisplayModes(mockOtherToken, DISPLAY_ID, requestedOtherModes)
+
+ val deathRecipientCaptor = argumentCaptor<IBinder.DeathRecipient>()
+ verify(mockOtherToken).linkToDeath(deathRecipientCaptor.capture(), eq(0))
+ deathRecipientCaptor.lastValue.binderDied(mockOtherToken)
+
+ val votes = storage.getVotes(DISPLAY_ID)
+ assertThat(votes.size()).isEqualTo(1)
+ val vote = votes.get(Vote.PRIORITY_SYSTEM_REQUESTED_MODES)
+ assertThat(vote).isInstanceOf(SupportedModesVote::class.java)
+ val supportedModesVote = vote as SupportedModesVote
+ assertThat(supportedModesVote.mModeIds.size).isEqualTo(requestedModes.size)
+ for (mode in requestedModes) {
+ assertThat(supportedModesVote.mModeIds).contains(mode)
+ }
+ }
+} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt
index 910e03c5db85..6b90bde188c5 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/TestUtils.kt
@@ -18,10 +18,10 @@ package com.android.server.display.mode
internal fun createVotesSummary(
isDisplayResolutionRangeVotingEnabled: Boolean = true,
- vsyncProximityVoteEnabled: Boolean = true,
+ supportedModesVoteEnabled: Boolean = true,
loggingEnabled: Boolean = true,
supportsFrameRateOverride: Boolean = true
): VoteSummary {
- return VoteSummary(isDisplayResolutionRangeVotingEnabled, vsyncProximityVoteEnabled,
+ return VoteSummary(isDisplayResolutionRangeVotingEnabled, supportedModesVoteEnabled,
loggingEnabled, supportsFrameRateOverride)
} \ No newline at end of file
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt
index d6c84690e65f..04b35f10545f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt
@@ -28,29 +28,29 @@ import org.junit.runner.RunWith
@RunWith(TestParameterInjector::class)
class VoteSummaryTest {
- enum class SupportedModesVoteTestCase(
- val vsyncProximityVoteEnabled: Boolean,
- internal val summarySupportedModes: List<SupportedModesVote.SupportedMode>?,
+ enum class SupportedRefreshRatesTestCase(
+ val supportedModesVoteEnabled: Boolean,
+ internal val summaryRefreshRates: List<SupportedRefreshRatesVote.RefreshRates>?,
val modesToFilter: Array<Display.Mode>,
val expectedModeIds: List<Int>
) {
HAS_NO_MATCHING_VOTE(true,
- listOf(SupportedModesVote.SupportedMode(60f, 60f)),
+ listOf(SupportedRefreshRatesVote.RefreshRates(60f, 60f)),
arrayOf(createMode(1, 90f, 90f),
createMode(2, 90f, 60f),
createMode(3, 60f, 90f)),
listOf()
),
HAS_SINGLE_MATCHING_VOTE(true,
- listOf(SupportedModesVote.SupportedMode(60f, 90f)),
+ listOf(SupportedRefreshRatesVote.RefreshRates(60f, 90f)),
arrayOf(createMode(1, 90f, 90f),
createMode(2, 90f, 60f),
createMode(3, 60f, 90f)),
listOf(3)
),
HAS_MULTIPLE_MATCHING_VOTES(true,
- listOf(SupportedModesVote.SupportedMode(60f, 90f),
- SupportedModesVote.SupportedMode(90f, 90f)),
+ listOf(SupportedRefreshRatesVote.RefreshRates(60f, 90f),
+ SupportedRefreshRatesVote.RefreshRates(90f, 90f)),
arrayOf(createMode(1, 90f, 90f),
createMode(2, 90f, 60f),
createMode(3, 60f, 90f)),
@@ -70,7 +70,69 @@ class VoteSummaryTest {
createMode(3, 60f, 90f)),
listOf(1, 2, 3)
),
- HAS_VSYNC_PROXIMITY_DISABLED(false,
+ HAS_SUPPORTED_MODES_VOTE_DISABLED(false,
+ listOf(),
+ arrayOf(createMode(1, 90f, 90f),
+ createMode(2, 90f, 60f),
+ createMode(3, 60f, 90f)),
+ listOf(1, 2, 3)
+ ),
+ }
+
+ @Test
+ fun `filters modes for summary supportedRefreshRates`(
+ @TestParameter testCase: SupportedRefreshRatesTestCase
+ ) {
+ val summary = createSummary(testCase.supportedModesVoteEnabled)
+ summary.supportedRefreshRates = testCase.summaryRefreshRates
+
+ val result = summary.filterModes(testCase.modesToFilter)
+
+ assertThat(result.map { it.modeId }).containsExactlyElementsIn(testCase.expectedModeIds)
+ }
+
+ enum class SupportedModesTestCase(
+ val supportedModesVoteEnabled: Boolean,
+ internal val summarySupportedModes: List<Int>?,
+ val modesToFilter: Array<Display.Mode>,
+ val expectedModeIds: List<Int>
+ ) {
+ HAS_NO_MATCHING_VOTE(true,
+ listOf(4, 5),
+ arrayOf(createMode(1, 90f, 90f),
+ createMode(2, 90f, 60f),
+ createMode(3, 60f, 90f)),
+ listOf()
+ ),
+ HAS_SINGLE_MATCHING_VOTE(true,
+ listOf(3),
+ arrayOf(createMode(1, 90f, 90f),
+ createMode(2, 90f, 60f),
+ createMode(3, 60f, 90f)),
+ listOf(3)
+ ),
+ HAS_MULTIPLE_MATCHING_VOTES(true,
+ listOf(1, 3),
+ arrayOf(createMode(1, 90f, 90f),
+ createMode(2, 90f, 60f),
+ createMode(3, 60f, 90f)),
+ listOf(1, 3)
+ ),
+ HAS_NO_SUPPORTED_MODES(true,
+ listOf(),
+ arrayOf(createMode(1, 90f, 90f),
+ createMode(2, 90f, 60f),
+ createMode(3, 60f, 90f)),
+ listOf()
+ ),
+ HAS_NULL_SUPPORTED_MODES(true,
+ null,
+ arrayOf(createMode(1, 90f, 90f),
+ createMode(2, 90f, 60f),
+ createMode(3, 60f, 90f)),
+ listOf(1, 2, 3)
+ ),
+ HAS_SUPPORTED_MODES_VOTE_DISABLED(false,
listOf(),
arrayOf(createMode(1, 90f, 90f),
createMode(2, 90f, 60f),
@@ -81,10 +143,10 @@ class VoteSummaryTest {
@Test
fun `filters modes for summary supportedModes`(
- @TestParameter testCase: SupportedModesVoteTestCase
+ @TestParameter testCase: SupportedModesTestCase
) {
- val summary = createSummary(testCase.vsyncProximityVoteEnabled)
- summary.supportedModes = testCase.summarySupportedModes
+ val summary = createSummary(testCase.supportedModesVoteEnabled)
+ summary.supportedModeIds = testCase.summarySupportedModes
val result = summary.filterModes(testCase.modesToFilter)
@@ -96,8 +158,8 @@ private fun createMode(modeId: Int, refreshRate: Float, vsyncRate: Float): Displ
FloatArray(0), IntArray(0))
}
-private fun createSummary(vsyncVoteEnabled: Boolean): VoteSummary {
- val summary = createVotesSummary(vsyncProximityVoteEnabled = vsyncVoteEnabled)
+private fun createSummary(supportedModesVoteEnabled: Boolean): VoteSummary {
+ val summary = createVotesSummary(supportedModesVoteEnabled = supportedModesVoteEnabled)
summary.width = 600
summary.height = 800
summary.maxPhysicalRefreshRate = Float.POSITIVE_INFINITY
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java
index 1f6f1a41bea7..a248d6de118f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java
@@ -18,6 +18,7 @@ package com.android.server.display.mode;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -153,4 +154,51 @@ public class VotesStorageTest {
assertThat(mVotesStorage.getVotes(DISPLAY_ID).size()).isEqualTo(0);
verify(mVotesListener, never()).onChanged();
}
+
+
+ @Test
+ public void removesAllVotesForPriority() {
+ // GIVEN vote storage with votes
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY_OTHER, VOTE_OTHER);
+ mVotesStorage.updateVote(DISPLAY_ID_OTHER, PRIORITY, VOTE);
+ mVotesStorage.updateVote(DISPLAY_ID_OTHER, PRIORITY_OTHER, VOTE_OTHER);
+ // WHEN removeAllVotesForPriority is called
+ mVotesStorage.removeAllVotesForPriority(PRIORITY);
+ // THEN votes with priority are removed from the storage
+ SparseArray<Vote> votes = mVotesStorage.getVotes(DISPLAY_ID);
+ assertThat(votes.size()).isEqualTo(1);
+ assertThat(votes.get(PRIORITY)).isNull();
+ votes = mVotesStorage.getVotes(DISPLAY_ID_OTHER);
+ assertThat(votes.size()).isEqualTo(1);
+ assertThat(votes.get(PRIORITY)).isNull();
+ }
+
+ @Test
+ public void removesAllVotesForPriority_notifiesListenerOnce() {
+ // GIVEN vote storage with votes
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY_OTHER, VOTE_OTHER);
+ mVotesStorage.updateVote(DISPLAY_ID_OTHER, PRIORITY, VOTE);
+ mVotesStorage.updateVote(DISPLAY_ID_OTHER, PRIORITY_OTHER, VOTE_OTHER);
+ clearInvocations(mVotesListener);
+ // WHEN removeAllVotesForPriority is called
+ mVotesStorage.removeAllVotesForPriority(PRIORITY);
+ // THEN listener notified once
+ verify(mVotesListener).onChanged();
+ }
+
+ @Test
+ public void removesAllVotesForPriority_noChangesIfNothingRemoved() {
+ // GIVEN vote storage with votes
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ clearInvocations(mVotesListener);
+ // WHEN removeAllVotesForPriority is called for missing priority
+ mVotesStorage.removeAllVotesForPriority(PRIORITY_OTHER);
+ // THEN no changes to votes storage
+ SparseArray<Vote> votes = mVotesStorage.getVotes(DISPLAY_ID);
+ assertThat(votes.size()).isEqualTo(1);
+ assertThat(votes.get(PRIORITY)).isEqualTo(VOTE);
+ verify(mVotesListener, never()).onChanged();
+ }
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index aec896f383c4..f86ff14218ba 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -64,6 +64,7 @@ import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.res.Resources;
import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
import android.hardware.display.AmbientDisplayConfiguration;
@@ -154,6 +155,8 @@ public class PowerManagerServiceTest {
private static final float BRIGHTNESS_FACTOR = 0.7f;
private static final boolean BATTERY_SAVER_ENABLED = true;
+ private static final DeviceState DEVICE_STATE_1 = new DeviceState(
+ new DeviceState.Configuration.Builder(1 /* identifier */, "" /* name */).build());
@Mock private BatterySaverController mBatterySaverControllerMock;
@Mock private BatterySaverPolicy mBatterySaverPolicyMock;
@@ -2839,7 +2842,7 @@ public class PowerManagerServiceTest {
// Send a display state change event and advance the clock 10.
final DeviceStateCallback deviceStateCallback = deviceStateCallbackCaptor.getValue();
- deviceStateCallback.onStateChanged(1);
+ deviceStateCallback.onDeviceStateChanged(DEVICE_STATE_1);
final long timeToAdvance = 10;
advanceTime(timeToAdvance);
@@ -2849,7 +2852,7 @@ public class PowerManagerServiceTest {
assertThat(mService.wasDeviceIdleForInternal(timeToAdvance)).isFalse();
// Send the same state and ensure that does not trigger an update.
- deviceStateCallback.onStateChanged(1);
+ deviceStateCallback.onDeviceStateChanged(DEVICE_STATE_1);
advanceTime(timeToAdvance);
final long newTime = timeToAdvance * 2;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 03b695d170ad..43b424fab907 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -1376,8 +1376,9 @@ public class WindowOrganizerTests extends WindowTestsBase {
assertTrue(w1.syncNextBuffer());
assertTrue(w2.syncNextBuffer());
- // A drawn window can complete the sync state automatically.
+ // A drawn window in non-explicit sync can complete the sync state automatically.
w1.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+ w1.mPrepareSyncSeqId = 0;
makeLastConfigReportedToClient(w1, true /* visible */);
mWm.mSyncEngine.onSurfacePlacement();
verify(mockCallback).onTransactionReady(anyInt(), any());
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 77b263824b78..9acda5f249d2 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -142,8 +142,6 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
"/sys/class/android_usb/android0/state";
private static final String RNDIS_ETH_ADDR_PATH =
"/sys/class/android_usb/android0/f_rndis/ethaddr";
- private static final String AUDIO_SOURCE_PCM_PATH =
- "/sys/class/android_usb/android0/f_audio_source/pcm";
private static final String MIDI_ALSA_PATH =
"/sys/class/android_usb/android0/f_midi/alsa";
@@ -172,8 +170,6 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
private static final int MSG_UPDATE_USB_SPEED = 22;
private static final int MSG_UPDATE_HAL_VERSION = 23;
- private static final int AUDIO_MODE_SOURCE = 1;
-
// Delay for debouncing USB disconnects.
// We often get rapid connect/disconnect events when enabling USB functions,
// which need debouncing.
@@ -464,7 +460,6 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
int operationId = sUsbOperationCount.incrementAndGet();
mAccessoryStrings = nativeGetAccessoryStrings();
- boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
// don't start accessory mode if our mandatory strings have not been set
boolean enableAccessory = (mAccessoryStrings != null &&
mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
@@ -474,9 +469,6 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
if (enableAccessory) {
functions |= UsbManager.FUNCTION_ACCESSORY;
}
- if (enableAudio) {
- functions |= UsbManager.FUNCTION_AUDIO_SOURCE;
- }
if (functions != UsbManager.FUNCTION_NONE) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSORY_MODE_ENTER_TIMEOUT),
@@ -2490,6 +2482,4 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
private native FileDescriptor nativeOpenControl(String usbFunction);
private native boolean nativeIsStartRequested();
-
- private native int nativeGetAudioMode();
}