summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/IUriGrantsManager.aidl3
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java88
-rw-r--r--core/java/android/inputmethodservice/NavigationBarController.java2
-rw-r--r--core/java/android/provider/Settings.java12
-rw-r--r--core/java/android/util/FeatureFlagUtils.java1
-rw-r--r--core/java/android/view/HandwritingInitiator.java34
-rw-r--r--core/java/android/view/ViewRootImpl.java45
-rw-r--r--core/java/android/view/WindowManager.java50
-rw-r--r--core/java/android/view/inputmethod/RemoteInputConnectionImpl.java38
-rw-r--r--core/java/android/webkit/WebView.java12
-rw-r--r--core/java/android/webkit/WebViewProvider.java10
-rw-r--r--core/java/android/widget/TextView.java15
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java6
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java2
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java4
-rw-r--r--core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java2
-rw-r--r--core/java/com/android/internal/util/SettingsWrapper.java36
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp13
-rw-r--r--core/proto/android/providers/settings/secure.proto1
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml2
-rw-r--r--core/res/res/values-da/strings.xml4
-rw-r--r--core/res/res/values-fr-rCA/strings.xml2
-rw-r--r--core/res/res/values-kn/strings.xml4
-rw-r--r--core/res/res/values-ky/strings.xml4
-rw-r--r--core/res/res/values-mn/strings.xml6
-rw-r--r--core/res/res/values-ms/strings.xml2
-rw-r--r--core/res/res/values-my/strings.xml2
-rw-r--r--core/res/res/values-nl/strings.xml2
-rw-r--r--core/res/res/values-pa/strings.xml2
-rw-r--r--core/res/res/values-ru/strings.xml2
-rw-r--r--core/res/res/values-sq/strings.xml4
-rw-r--r--core/res/res/values-sr/strings.xml2
-rw-r--r--core/res/res/values-te/strings.xml2
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java21
-rw-r--r--core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java19
-rw-r--r--data/etc/services.core.protolog.json18
-rw-r--r--libs/WindowManager/Shell/res/values-be/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings.xml6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java65
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java9
-rw-r--r--packages/CredentialManager/res/values-b+sr+Latn/strings.xml4
-rw-r--r--packages/CredentialManager/res/values-in/strings.xml2
-rw-r--r--packages/CredentialManager/res/values-sr/strings.xml4
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt12
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt4
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java4
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml6
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java19
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java45
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java43
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java75
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java86
-rw-r--r--packages/SystemUI/OWNERS6
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/res/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt33
-rw-r--r--packages/SystemUI/ktfmt_includes.txt1
-rw-r--r--packages/SystemUI/res/layout/media_projection_app_selector.xml3
-rw-r--r--packages/SystemUI/res/values-da/strings.xml12
-rw-r--r--packages/SystemUI/res/values-it/strings.xml4
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml6
-rw-r--r--packages/SystemUI/res/values-kn/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml2
-rw-r--r--packages/SystemUI/res/values-my/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml1
-rw-r--r--packages/SystemUI/res/values/ids.xml4
-rw-r--r--packages/SystemUI/res/values/strings.xml10
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt100
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java240
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt97
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt12
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java110
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java28
-rw-r--r--services/core/java/com/android/server/audio/SoundDoseHelper.java5
-rw-r--r--services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java47
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java6
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java6
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java9
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java3
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController2.java5
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java11
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java29
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingModeController.java1
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java47
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java7
-rw-r--r--services/core/java/com/android/server/timedetector/ConfigurationInternal.java5
-rw-r--r--services/core/java/com/android/server/timedetector/EnvironmentImpl.java38
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java29
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java44
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java175
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java42
-rw-r--r--services/core/java/com/android/server/utils/FoldSettingProvider.java102
-rw-r--r--services/core/java/com/android/server/utils/FoldSettingWrapper.java48
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java27
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/ContentRecorder.java41
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java16
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java99
-rw-r--r--services/core/java/com/android/server/wm/LetterboxConfiguration.java4
-rw-r--r--services/core/java/com/android/server/wm/Session.java5
-rw-r--r--services/core/java/com/android/server/wm/Transition.java5
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java23
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java31
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java20
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java15
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java15
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java64
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java54
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java143
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java31
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java36
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java40
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java153
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java141
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java55
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java6
-rw-r--r--services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java30
187 files changed, 2982 insertions, 916 deletions
diff --git a/core/java/android/app/IUriGrantsManager.aidl b/core/java/android/app/IUriGrantsManager.aidl
index 9e7f2fecfea0..b630d034dca9 100644
--- a/core/java/android/app/IUriGrantsManager.aidl
+++ b/core/java/android/app/IUriGrantsManager.aidl
@@ -39,4 +39,7 @@ interface IUriGrantsManager {
void clearGrantedUriPermissions(in String packageName, int userId);
ParceledListSlice getUriPermissions(in String packageName, boolean incoming,
boolean persistedOnly);
+
+ int checkGrantUriPermission_ignoreNonSystem(
+ int sourceUid, String targetPkg, in Uri uri, int modeFlags, int userId);
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 0e45787c1340..2eed993eb769 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -633,12 +633,13 @@ public abstract class CameraDevice implements AutoCloseable {
* <style scoped>
* #rb { border-right-width: thick; }
* </style>
+ *
+ * <h5>LEGACY-level guaranteed configurations</h5>
+ *
* <p>Legacy devices ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}) support at
* least the following stream combinations:
*
- * <h5>LEGACY-level guaranteed configurations</h5>
- *
* <table>
* <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th> <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
@@ -653,13 +654,13 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
+ * <h5>LIMITED-level additional guaranteed configurations</h5>
+ *
* <p>Limited-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices
* support at least the following stream combinations in addition to those for
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} devices:
*
- * <h5>LIMITED-level additional guaranteed configurations</h5>
- *
* <table>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
@@ -672,13 +673,13 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
+ * <h5>FULL-level additional guaranteed configurations</h5>
+ *
* <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
* support at least the following stream combinations in addition to those for
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
*
- * <h5>FULL-level additional guaranteed configurations</h5>
- *
* <table>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -691,14 +692,14 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
+ * <h5>RAW-capability additional guaranteed configurations</h5>
+ *
* <p>RAW-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
* {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}) devices additionally support
* at least the following stream combinations on both
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
*
- * <h5>RAW-capability additional guaranteed configurations</h5>
- *
* <table>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -713,6 +714,8 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
+ * <h5>BURST-capability additional guaranteed configurations</h5>
+ *
* <p>BURST-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
* {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}) devices
* support at least the below stream combinations in addition to those for
@@ -721,8 +724,6 @@ public abstract class CameraDevice implements AutoCloseable {
* list for FULL-level devices, so this table is only relevant for LIMITED-level devices that
* support the BURST_CAPTURE capability.
*
- * <h5>BURST-capability additional guaranteed configurations</h5>
- *
* <table>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -732,6 +733,8 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
+ * <h5>LEVEL-3 additional guaranteed configurations</h5>
+ *
* <p>LEVEL-3 ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL_3})
* support at least the following stream combinations in addition to the combinations for
@@ -739,8 +742,6 @@ public abstract class CameraDevice implements AutoCloseable {
* RAW capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
* {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}):
*
- * <h5>LEVEL-3 additional guaranteed configurations</h5>
- *
* <table>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -749,14 +750,16 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
- *<p>BACKWARD_COMPATIBLE devices capable of streaming concurrently with other devices as described by
- * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the
+ * <h5>Concurrent stream guaranteed configurations</h5>
+ *
+ * <p>BACKWARD_COMPATIBLE devices capable of streaming concurrently with other devices as
+ * described by {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the
* following guaranteed streams (when streaming concurrently with other devices)</p>
+ *
* <p> Note: The sizes mentioned for these concurrent streams are the maximum sizes guaranteed
* to be supported. Sizes smaller than these, obtained by {@link StreamConfigurationMap#getOutputSizes} for a particular format, are supported as well. </p>
*
- * <h5>Concurrent stream guaranteed configurations</h5>
- *
+ * <p>
* <table>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -792,6 +795,8 @@ public abstract class CameraDevice implements AutoCloseable {
* level and capabilities. Calling createCaptureSession with both JPEG and HEIC outputs is not
* supported.</p>
*
+ * <h5>LEGACY-level additional guaranteed combinations with multi-resolution outputs</h5>
+ *
* <p>Devices capable of multi-resolution output for a particular format (
* {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo}
* returns a non-empty list) support using {@link MultiResolutionImageReader} for MAXIMUM
@@ -802,8 +807,6 @@ public abstract class CameraDevice implements AutoCloseable {
* stream combinations ({@code MULTI_RES} in the Max size column refers to a {@link
* MultiResolutionImageReader} created based on the variable max resolutions supported):
*
- * <h5>LEGACY-level additional guaranteed combinations with MultiResolutionoutputs</h5>
- *
* <table>
* <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th> <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
@@ -812,8 +815,12 @@ public abstract class CameraDevice implements AutoCloseable {
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Still capture plus in-app processing.</td> </tr>
* </table><br>
+ * </p>
+ *
+ * <h5>LIMITED-level additional guaranteed configurations with multi-resolution outputs</h5>
+ *
+ * <p>
* <table>
- * <tr><th colspan="7">LIMITED-level additional guaranteed configurations with MultiResolutionoutputs</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
* <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Two-input in-app processing with still capture.</td> </tr>
@@ -821,11 +828,11 @@ public abstract class CameraDevice implements AutoCloseable {
* The same logic applies to other hardware levels and capabilities.
* </p>
*
- * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees
- * which clients can take advantage of : </p>
- *
* <h5>Additional guaranteed combinations for ULTRA_HIGH_RESOLUTION sensors</h5>
*
+ * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees
+ * which clients can take advantage of:
+ *
* <table>
* <tr> <th colspan="3" id="rb">Target 1</th> <th colspan="3" id="rb">Target 2</th> <th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th></tr>
@@ -833,6 +840,7 @@ public abstract class CameraDevice implements AutoCloseable {
* <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PRIV / YUV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code RECORD}</td> <td>Ultra high res still capture with preview + app based RECORD size analysis</td> </tr>
* <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code JPEG / YUV / RAW}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code MAX}</td> <td>Ultra high res still image capture with preview + default sensor pixel mode analysis stream</td> </tr>
* </table><br>
+ * </p>
*
* <p> Here, SC Map, refers to the {@link StreamConfigurationMap}, the target stream sizes must
* be chosen from. {@code DEFAULT} refers to the default sensor pixel mode {@link
@@ -842,17 +850,17 @@ public abstract class CameraDevice implements AutoCloseable {
* Note: The same capture request must not mix targets from
* {@link StreamConfigurationMap}s corresponding to different sensor pixel modes. </p>
*
- * <p> 10-bit output capable
- * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
- * devices support at least the following stream combinations: </p>
- *
* <h5>10-bit output additional guaranteed configurations</h5>
*
+ * <p>10-bit output capable
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
+ * devices support at least the following stream combinations:
+ *
* <table>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
- * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
- * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>In-application video/image processing.</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> </td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
+ * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> </td> <td colspan="4" id="rb"></td> <td>In-application video/image processing.</td> </tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution in-app processing with preview.</td> </tr>
* <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution two-input in-app processing.</td> </tr>
@@ -860,6 +868,8 @@ public abstract class CameraDevice implements AutoCloseable {
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code RECORD }</td> <td>{@code YUV}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with in-app snapshot.</td> </tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV }</td><td id="rb">{@code RECORD }</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with video snapshot.</td> </tr>
* </table><br>
+ * </p>
+ *
* <p>Here PRIV can be either 8 or 10-bit {@link android.graphics.ImageFormat#PRIVATE} pixel
* format. YUV can be either {@link android.graphics.ImageFormat#YUV_420_888} or
* {@link android.graphics.ImageFormat#YCBCR_P010}.
@@ -895,13 +905,13 @@ public abstract class CameraDevice implements AutoCloseable {
* {@link CameraDevice#isSessionConfigurationSupported} to ensure that this particular
* configuration is supported.</p>
*
+ * <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5>
+ *
* <p>Devices with the STREAM_USE_CASE capability ({@link
* CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes {@link
* CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}) support below additional
* stream combinations:
*
- * <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5>
- *
* <table>
* <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr>
@@ -921,12 +931,12 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
+ * <h5>STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</h5>
+ *
* <p>Devices that include the {@link CameraMetadata#SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW}
* stream use-case in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES},
* support the additional stream combinations below:
*
- * <h5>STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</h5>
- *
* <table>
* <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr>
@@ -934,15 +944,17 @@ public abstract class CameraDevice implements AutoCloseable {
* <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td colspan="3" id="rb"></td> <td>Preview with cropped RAW still capture</td> </tr>
* <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td>Preview with YUV / JPEG and cropped RAW still capture</td> </tr>
* <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code VIDEO_RECORD / PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td>Video recording with preview and cropped RAW still capture</td> </tr>
+ * </table><br>
+ * </p>
*
+ * <h5>Preview stabilization guaranteed stream configurations</h5>
*
- *<p> For devices where {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES}
- * includes {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION},
+ * <p>For devices where
+ * {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES} includes
+ * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION},
* the following stream combinations are guaranteed,
* for CaptureRequests where {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE} is set to
- * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION} <p>
- *
- * <h5>Preview stabilization guaranteed stream configurations</h5>
+ * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION}
*
* <table>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
@@ -951,6 +963,8 @@ public abstract class CameraDevice implements AutoCloseable {
* <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p}</td> <td>{@code JPEG / YUV}</td><td id="rb">{@code MAXIMUM }</td><td>Standard still imaging with stabilized preview.</td> </tr>
* <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p }</td><td>High-resolution recording with stabilized preview and recording stream.</td> </tr>
* </table><br>
+ * </p>
+ *
* <p>
* For the maximum size column, PREVIEW refers to the best size match to the device's screen
* resolution, or to 1080p (1920x1080), whichever is smaller. RECORD refers to the camera
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index c01664e55744..8be4c5858694 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -237,7 +237,7 @@ final class NavigationBarController {
mNavigationBarFrame.setOnApplyWindowInsetsListener((view, insets) -> {
if (mNavigationBarFrame != null) {
boolean visible = insets.isVisible(captionBar());
- mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.GONE);
}
return view.onApplyWindowInsets(insets);
});
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d66ffcebae5e..a55183c0f7c5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4724,13 +4724,13 @@ public final class Settings {
public static final String PEAK_REFRESH_RATE = "peak_refresh_rate";
/**
- * Control whether to stay awake on fold
+ * Control lock behavior on fold
*
* If this isn't set, the system falls back to a device specific default.
* @hide
*/
@Readable
- public static final String STAY_AWAKE_ON_FOLD = "stay_awake_on_fold";
+ public static final String FOLD_LOCK_BEHAVIOR = "fold_lock_behavior_setting";
/**
* The amount of time in milliseconds before the device goes to sleep or begins
@@ -10505,6 +10505,14 @@ public final class Settings {
"search_press_hold_nav_handle_enabled";
/**
+ * Whether long-pressing on the home button can trigger search.
+ *
+ * @hide
+ */
+ public static final String SEARCH_LONG_PRESS_HOME_ENABLED =
+ "search_long_press_home_enabled";
+
+ /**
* Control whether Trust Agents are in active unlock or extend unlock mode.
* @hide
*/
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 85f5395f2657..827600c83fae 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -247,7 +247,6 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "true");
DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "true");
DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS, "false");
- DEFAULT_FLAGS.put("settings_press_hold_nav_handle_to_search", "false");
}
private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 297754f7a5fd..dfade0167e22 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -24,6 +24,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
@@ -81,6 +82,8 @@ public class HandwritingInitiator {
private int mConnectionCount = 0;
private final InputMethodManager mImm;
+ private final int[] mTempLocation = new int[2];
+
private final Rect mTempRect = new Rect();
private final RectF mTempRectF = new RectF();
@@ -429,7 +432,19 @@ public class HandwritingInitiator {
return null;
}
- private static void requestFocusWithoutReveal(View view) {
+ private void requestFocusWithoutReveal(View view) {
+ if (view instanceof EditText editText && !mState.mStylusDownWithinEditorBounds) {
+ // If the stylus down point was inside the EditText's bounds, then the EditText will
+ // automatically set its cursor position nearest to the stylus down point when it
+ // gains focus. If the stylus down point was outside the EditText's bounds (within
+ // the extended handwriting bounds), then we must calculate and set the cursor
+ // position manually.
+ view.getLocationInWindow(mTempLocation);
+ int offset = editText.getOffsetForPosition(
+ mState.mStylusDownX - mTempLocation[0],
+ mState.mStylusDownY - mTempLocation[1]);
+ editText.setSelection(offset);
+ }
if (view.getRevealOnFocusHint()) {
view.setRevealOnFocusHint(false);
view.requestFocus();
@@ -457,6 +472,10 @@ public class HandwritingInitiator {
if (getViewHandwritingArea(connectedView, handwritingArea)
&& isInHandwritingArea(handwritingArea, x, y, connectedView, isHover)
&& shouldTriggerStylusHandwritingForView(connectedView)) {
+ if (!isHover && mState != null) {
+ mState.mStylusDownWithinEditorBounds =
+ contains(handwritingArea, x, y, 0f, 0f, 0f, 0f);
+ }
return connectedView;
}
}
@@ -475,7 +494,12 @@ public class HandwritingInitiator {
}
final float distance = distance(handwritingArea, x, y);
- if (distance == 0f) return view;
+ if (distance == 0f) {
+ if (!isHover && mState != null) {
+ mState.mStylusDownWithinEditorBounds = true;
+ }
+ return view;
+ }
if (distance < minDistance) {
minDistance = distance;
bestCandidate = view;
@@ -658,6 +682,12 @@ public class HandwritingInitiator {
private boolean mExceedHandwritingSlop;
/**
+ * Whether the stylus down point of the MotionEvent sequence was within the editor's bounds
+ * (not including the extended handwriting bounds).
+ */
+ private boolean mStylusDownWithinEditorBounds;
+
+ /**
* A view which has requested focus and is pending input connection creation. When an input
* connection is created for the view, a handwriting session should be started for the view.
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d680d0432f25..c2afb4bf5205 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -434,15 +434,15 @@ public final class ViewRootImpl implements ViewParent,
/**
* Called when the typing hint is changed. This would be invoked by the
* {@link android.view.inputmethod.RemoteInputConnectionImpl}
- * to hint if the user is typing when the it is {@link #isActive() active}.
+ * to hint if the user is typing when it is {@link #isActive() active}.
*
- * This can be only happened on the UI thread. The behavior won't be guaranteed if
- * invoking this on a non-UI thread.
+ * The operation in this method should be dispatched to the UI thread to
+ * keep the sequence.
*
* @param isTyping {@code true} if the user is typing.
+ * @param deactivate {code true} if the input connection deactivate
*/
- @UiThread
- void onTypingHintChanged(boolean isTyping);
+ void onTypingHintChanged(boolean isTyping, boolean deactivate);
/**
* Indicates whether the notifier is currently in active state or not.
@@ -468,19 +468,40 @@ public final class ViewRootImpl implements ViewParent,
@NonNull
private final ViewRootRefreshRateController mController;
+ @NonNull
+ private final Handler mHandler;
+
+ @NonNull
+ private final Thread mThread;
+
TypingHintNotifierImpl(@NonNull AtomicReference<TypingHintNotifier> notifier,
- @NonNull ViewRootRefreshRateController controller) {
+ @NonNull ViewRootRefreshRateController controller, @NonNull Handler handler,
+ @NonNull Thread thread) {
mController = controller;
mActiveNotifier = notifier;
+ mHandler = handler;
+ mThread = thread;
}
@Override
- public void onTypingHintChanged(boolean isTyping) {
- if (!isActive()) {
- // No-op when the listener was deactivated.
- return;
+ public void onTypingHintChanged(boolean isTyping, boolean deactivate) {
+ final Runnable runnable = () -> {
+ if (!isActive()) {
+ // No-op when the listener was deactivated.
+ return;
+ }
+ mController.updateRefreshRatePreference(isTyping ? LOWER : RESTORE);
+ if (deactivate) {
+ deactivate();
+ }
+ };
+
+ if (Thread.currentThread() == mThread) {
+ // Run directly if it's on the UiThread.
+ runnable.run();
+ } else {
+ mHandler.post(runnable);
}
- mController.updateRefreshRatePreference(isTyping ? LOWER : RESTORE);
}
@Override
@@ -521,7 +542,7 @@ public final class ViewRootImpl implements ViewParent,
return null;
}
final TypingHintNotifier newNotifier = new TypingHintNotifierImpl(mActiveTypingHintNotifier,
- mRefreshRateController);
+ mRefreshRateController, mHandler, mThread);
mActiveTypingHintNotifier.set(newNotifier);
return newNotifier;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 30bdd95c28d1..c00924b61a34 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3139,15 +3139,6 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS = 1 << 10;
/**
- * Flag to force the status bar window to be visible all the time. If the bar is hidden when
- * this flag is set it will be shown again.
- * This can only be set by {@link LayoutParams#TYPE_STATUS_BAR}.
- *
- * {@hide}
- */
- public static final int PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR = 1 << 11;
-
- /**
* Flag to indicate that the window frame should be the requested frame adding the display
* cutout frame. This will only be applied if a specific size smaller than the parent frame
* is given, and the window is covering the display cutout. The extended frame will not be
@@ -3238,15 +3229,6 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_NOT_MAGNIFIABLE = 1 << 22;
/**
- * Flag to indicate that the status bar window is in a state such that it forces showing
- * the navigation bar unless the navigation bar window is explicitly set to
- * {@link View#GONE}.
- * It only takes effects if this is set by {@link LayoutParams#TYPE_STATUS_BAR}.
- * @hide
- */
- public static final int PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION = 1 << 23;
-
- /**
* Flag to indicate that the window is color space agnostic, and the color can be
* interpreted to any color space.
* @hide
@@ -3334,7 +3316,6 @@ public interface WindowManager extends ViewManager {
PRIVATE_FLAG_SYSTEM_ERROR,
PRIVATE_FLAG_OPTIMIZE_MEASURE,
PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS,
- PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT,
PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY,
PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME,
@@ -3345,7 +3326,6 @@ public interface WindowManager extends ViewManager {
PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION,
PRIVATE_FLAG_NOT_MAGNIFIABLE,
- PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
PRIVATE_FLAG_USE_BLAST,
PRIVATE_FLAG_APPEARANCE_CONTROLLED,
@@ -3401,10 +3381,6 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS,
name = "DISABLE_WALLPAPER_TOUCH_EVENTS"),
@ViewDebug.FlagToString(
- mask = PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
- equals = PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
- name = "FORCE_STATUS_BAR_VISIBLE"),
- @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT,
equals = PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT,
name = "LAYOUT_SIZE_EXTENDED_BY_CUTOUT"),
@@ -3445,10 +3421,6 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_NOT_MAGNIFIABLE,
name = "NOT_MAGNIFIABLE"),
@ViewDebug.FlagToString(
- mask = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
- equals = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
- name = "STATUS_FORCE_SHOW_NAVIGATION"),
- @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
equals = PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
name = "COLOR_SPACE_AGNOSTIC"),
@@ -4412,6 +4384,16 @@ public interface WindowManager extends ViewManager {
public InsetsFrameProvider[] providedInsets;
/**
+ * Specifies which {@link InsetsType}s should be forcibly shown. The types shown by this
+ * method won't affect the app's layout. This field only takes effects if the caller has
+ * {@link android.Manifest.permission#STATUS_BAR_SERVICE} or the caller has the same uid as
+ * the recents component.
+ *
+ * @hide
+ */
+ public @InsetsType int forciblyShownTypes;
+
+ /**
* {@link LayoutParams} to be applied to the window when layout with a assigned rotation.
* This will make layout during rotation change smoothly.
*
@@ -4869,6 +4851,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(mBlurBehindRadius);
out.writeBoolean(mWallpaperTouchEventsEnabled);
out.writeTypedArray(providedInsets, 0 /* parcelableFlags */);
+ out.writeInt(forciblyShownTypes);
checkNonRecursiveParams();
out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
out.writeInt(mDisplayFlags);
@@ -4940,6 +4923,7 @@ public interface WindowManager extends ViewManager {
mBlurBehindRadius = in.readInt();
mWallpaperTouchEventsEnabled = in.readBoolean();
providedInsets = in.createTypedArray(InsetsFrameProvider.CREATOR);
+ forciblyShownTypes = in.readInt();
paramsForRotation = in.createTypedArray(LayoutParams.CREATOR);
mDisplayFlags = in.readInt();
}
@@ -5245,6 +5229,11 @@ public interface WindowManager extends ViewManager {
changes |= LAYOUT_CHANGED;
}
+ if (forciblyShownTypes != o.forciblyShownTypes) {
+ forciblyShownTypes = o.forciblyShownTypes;
+ changes |= PRIVATE_FLAGS_CHANGED;
+ }
+
if (paramsForRotation != o.paramsForRotation) {
if ((changes & LAYOUT_CHANGED) == 0) {
if (paramsForRotation != null && o.paramsForRotation != null
@@ -5482,6 +5471,11 @@ public interface WindowManager extends ViewManager {
sb.append(prefix).append(" ").append(providedInsets[i]);
}
}
+ if (forciblyShownTypes != 0) {
+ sb.append(System.lineSeparator());
+ sb.append(prefix).append(" forciblyShownTypes=").append(
+ WindowInsets.Type.toString(forciblyShownTypes));
+ }
if (paramsForRotation != null && paramsForRotation.length != 0) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" paramsForRotation:");
diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
index 364adc77f7d3..3ad49afb1575 100644
--- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
@@ -28,8 +28,12 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UiThread;
+import android.app.UriGrantsManager;
+import android.content.ContentProvider;
+import android.content.Intent;
import android.graphics.RectF;
+import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.CancellationSignalBeamer;
@@ -38,6 +42,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.ResultReceiver;
import android.os.Trace;
+import android.os.UserHandle;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
@@ -373,11 +378,8 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
return;
}
dispatch(() -> {
- notifyTypingHint(false /* isTyping */);
// Deactivate the notifier when finishing typing.
- if (mTypingHintNotifier != null) {
- mTypingHintNotifier.deactivate();
- }
+ notifyTypingHint(false /* isTyping */, true /* deactivate */);
// Note that we do not need to worry about race condition here, because 1) mFinished is
// updated only inside this block, and 2) the code here is running on a Handler hence we
@@ -643,7 +645,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
return;
}
ic.commitText(text, newCursorPosition);
- notifyTypingHint(true /* isTyping */);
+ notifyTypingHint(true /* isTyping */, false /* deactivate */);
});
}
@@ -799,7 +801,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
return;
}
ic.setComposingText(text, newCursorPosition);
- notifyTypingHint(true /* isTyping */);
+ notifyTypingHint(true /* isTyping */, false /* deactivate */);
});
}
@@ -927,7 +929,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
return;
}
ic.deleteSurroundingText(beforeLength, afterLength);
- notifyTypingHint(true /* isTyping */);
+ notifyTypingHint(true /* isTyping */, false /* deactivate */);
});
}
@@ -1197,7 +1199,22 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
public void commitContent(InputConnectionCommandHeader header,
InputContentInfo inputContentInfo, int flags, Bundle opts,
AndroidFuture future /* T=Boolean */) {
+ final int imeUid = Binder.getCallingUid();
dispatchWithTracing("commitContent", future, () -> {
+ // Check if the originator IME has the right permissions
+ try {
+ final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(
+ inputContentInfo.getContentUri(), UserHandle.getUserId(imeUid));
+ final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(
+ inputContentInfo.getContentUri());
+ UriGrantsManager.getService().checkGrantUriPermission_ignoreNonSystem(imeUid, null,
+ contentUriWithoutUserId, Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ contentUriOwnerUserId);
+ } catch (Exception e) {
+ Log.w(TAG, "commitContent with invalid Uri permission from IME:", e);
+ return false;
+ }
+
if (header.mSessionId != mCurrentSessionId.get()) {
return false; // cancelled
}
@@ -1497,10 +1514,9 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
* The input connection indicates that the user is typing when {@link #commitText} or
* {@link #setComposingText)} and the user finish typing when {@link #deactivate()}.
*/
- @UiThread
- private void notifyTypingHint(boolean isTyping) {
+ private void notifyTypingHint(boolean isTyping, boolean deactivate) {
if (mTypingHintNotifier != null) {
- mTypingHintNotifier.onTypingHintChanged(isTyping);
+ mTypingHintNotifier.onTypingHintChanged(isTyping, deactivate);
}
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6523fffc4b91..f5b81b027134 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -50,6 +50,7 @@ import android.util.SparseArray;
import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
@@ -3139,4 +3140,15 @@ public class WebView extends AbsoluteLayout
if (result == null) return super.onApplyWindowInsets(insets);
return result;
}
+
+ @Override
+ @Nullable
+ public PointerIcon onResolvePointerIcon(@NonNull MotionEvent event, int pointerIndex) {
+ PointerIcon icon =
+ mProvider.getViewDelegate().onResolvePointerIcon(event, pointerIndex);
+ if (icon != null) {
+ return icon;
+ }
+ return super.onResolvePointerIcon(event, pointerIndex);
+ }
}
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 26579c5dec68..ca423e030044 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -39,6 +39,7 @@ import android.util.SparseArray;
import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowInsets;
@@ -496,6 +497,15 @@ public interface WebViewProvider {
default WindowInsets onApplyWindowInsets(@Nullable WindowInsets insets) {
return null;
}
+
+ /**
+ * @hide Only used by WebView.
+ */
+ @SuppressWarnings("unused")
+ @Nullable
+ default PointerIcon onResolvePointerIcon(@NonNull MotionEvent event, int pointerIndex) {
+ return null;
+ }
}
interface ScrollDelegate {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2ad3f74fcb7b..63e882533a4c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12888,6 +12888,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * @return true if this TextView could be filled by an Autofill service. Note that disabled
+ * fields can still be filled.
+ */
+ @UnsupportedAppUsage
+ boolean isTextAutofillable() {
+ return mText instanceof Editable && onCheckIsTextEditor();
+ }
+
+ /**
* Returns true, only while processing a touch gesture, if the initial
* touch down event caused focus to move to the text view and as a result
* its selection changed. Only valid while processing the touch gesture
@@ -13610,7 +13619,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void autofill(AutofillValue value) {
- if (!isTextEditable()) {
+ if (!isTextAutofillable()) {
Log.w(LOG_TAG, "cannot autofill non-editable TextView: " + this);
return;
}
@@ -13626,7 +13635,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public @AutofillType int getAutofillType() {
- return isTextEditable() ? AUTOFILL_TYPE_TEXT : AUTOFILL_TYPE_NONE;
+ return isTextAutofillable() ? AUTOFILL_TYPE_TEXT : AUTOFILL_TYPE_NONE;
}
/**
@@ -13640,7 +13649,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
@Nullable
public AutofillValue getAutofillValue() {
- if (isTextEditable()) {
+ if (isTextAutofillable()) {
final CharSequence text = TextUtils.trimToParcelableSize(getText());
return AutofillValue.forText(text);
}
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index 5e2eceb23789..dee49350d93e 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -177,7 +177,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
* <code>1</code> would return the work profile {@link ProfileDescriptor}.</li>
* </ul>
*/
- abstract ProfileDescriptor getItem(int pageIndex);
+ public abstract ProfileDescriptor getItem(int pageIndex);
/**
* Returns the number of {@link ProfileDescriptor} objects.
@@ -438,8 +438,8 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
&& isQuietModeEnabled(mWorkProfileUserHandle));
}
- protected class ProfileDescriptor {
- final ViewGroup rootView;
+ public static class ProfileDescriptor {
+ public final ViewGroup rootView;
private final ViewGroup mEmptyStateView;
ProfileDescriptor(ViewGroup rootView) {
this.rootView = rootView;
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 7beb059fb648..8197e265ca29 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -94,7 +94,7 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
}
@Override
- ChooserProfileDescriptor getItem(int pageIndex) {
+ public ChooserProfileDescriptor getItem(int pageIndex) {
return mItems[pageIndex];
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ac15f11ee989..7534d2960b7c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -2623,13 +2623,13 @@ public class ResolverActivity extends Activity implements
* An a11y delegate that expands resolver drawer when gesture navigation reaches a partially
* invisible target in the list.
*/
- private static class AppListAccessibilityDelegate extends View.AccessibilityDelegate {
+ public static class AppListAccessibilityDelegate extends View.AccessibilityDelegate {
private final ResolverDrawerLayout mDrawer;
@Nullable
private final View mBottomBar;
private final Rect mRect = new Rect();
- private AppListAccessibilityDelegate(ResolverDrawerLayout drawer) {
+ public AppListAccessibilityDelegate(ResolverDrawerLayout drawer) {
mDrawer = drawer;
mBottomBar = mDrawer.findViewById(R.id.button_bar_container);
}
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index 767791263673..031f9d3168bf 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -79,7 +79,7 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA
}
@Override
- ResolverProfileDescriptor getItem(int pageIndex) {
+ public ResolverProfileDescriptor getItem(int pageIndex) {
return mItems[pageIndex];
}
diff --git a/core/java/com/android/internal/util/SettingsWrapper.java b/core/java/com/android/internal/util/SettingsWrapper.java
new file mode 100644
index 000000000000..8cf6c18adb3a
--- /dev/null
+++ b/core/java/com/android/internal/util/SettingsWrapper.java
@@ -0,0 +1,36 @@
+/*
+ * 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.internal.util;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+/**
+ * A wrapper class for accessing and modifying system settings that would help with testing.
+ */
+public class SettingsWrapper {
+
+ /** Retrieves the string value of a system setting */
+ public String getStringForUser(ContentResolver contentResolver, String name, int userHandle) {
+ return Settings.System.getStringForUser(contentResolver, name, userHandle);
+ }
+
+ /** Updates the string value of a system setting */
+ public String putStringForUser(ContentResolver contentResolver, String name, int userHandle) {
+ return Settings.System.getStringForUser(contentResolver, name, userHandle);
+ }
+}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index c368fa85c379..56066b2d813c 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1806,15 +1806,10 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
if (!is_system_server && getuid() == 0) {
const int rc = createProcessGroup(uid, getpid());
if (rc != 0) {
- if (rc == -ESRCH) {
- // If process is dead, treat this as a non-fatal error
- ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
- } else {
- fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
- "CONFIG_CGROUP_CPUACCT?")
- : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid,
- /* pid= */ 0, strerror(-rc)));
- }
+ fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
+ "CONFIG_CGROUP_CPUACCT?")
+ : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid,
+ /* pid= */ 0, strerror(-rc)));
}
}
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 481a2fbd546f..f425c60b2d76 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -138,6 +138,7 @@ message SecureSettingsProto {
optional SettingProto touch_gesture_enabled = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto long_press_home_enabled = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto search_press_hold_nav_handle_enabled = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto search_long_press_home_enabled = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Assist assist = 7;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7d1253ccb687..8c9a3ff5149f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1467,10 +1467,9 @@
<!-- Allows an application to initiate a phone call without going through
the Dialer user interface for the user to confirm the call.
- <p>
- <em>Note: An app holding this permission can also call carrier MMI codes to change settings
- such as call forwarding or call waiting preferences.
- <p>Protection level: dangerous
+ <p class="note"><b>Note:</b> An app holding this permission can also call carrier MMI
+ codes to change settings such as call forwarding or call waiting preferences.</p>
+ <p>Protection level: dangerous</p>
-->
<permission android:name="android.permission.CALL_PHONE"
android:permissionGroup="android.permission-group.UNDEFINED"
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index fa4b1a123660..111451e10170 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -805,7 +805,7 @@
<string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"Dozvoljava vlasniku da ažurira aplikaciju koju je prethodno instalirala bez radnji korisnika"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Podešavanje pravila za lozinku"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontroliše dužinu i znakove dozvoljene u lozinkama i PIN-ovima za zaključavanje ekrana."</string>
- <string name="policylab_watchLogin" msgid="7599669460083719504">"Nadgledajte pokušaje otključavanja ekrana"</string>
+ <string name="policylab_watchLogin" msgid="7599669460083719504">"Nadzor pokušaja otključavanja ekrana"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Prati broj netačno unetih lozinki prilikom otključavanja ekrana i zaključava tablet ili briše podatke sa tableta ako je netačna lozinka uneta previše puta."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava Android TV uređaj ili briše sve podatke sa Android TV uređaja ako se unese previše netačnih lozinki."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Prati broj netačno unetih lozinki pri otključavanju ekrana i zaključava sistem za info-zabavu ili briše sve podatke sa sistema za info-zabavu ako je netačna lozinka uneta previše puta."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 619511087de1..fe82a73ced82 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -670,12 +670,12 @@
<string name="device_unlock_notification_name" msgid="2632928999862915709">"Enhedsoplåsning"</string>
<string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Prøv en anden metode til oplåsning"</string>
<string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Brug ansigtsoplåsning, hvis dit fingeraftryk ikke genkendes, f.eks. når du har våde fingre"</string>
- <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Brug oplåsning med fingeraftryk, hvis dit ansigt ikke genkendes, f.eks. når der ikke er nok lys"</string>
+ <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Brug fingeroplåsning, hvis dit ansigt ikke genkendes, f.eks. når der ikke er nok lys"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansigtsoplåsning"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Der er et problem med Ansigtsoplåsning"</string>
<string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Tryk for at slette din ansigtsmodel, og tilføj derefter dit ansigt igen"</string>
<string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Hvis du vil bruge ansigtsoplåsning, skal du aktivere "<b>"Kameraadgang"</b>" under Indstillinger &gt; Privatliv"</string>
- <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Oplåsning med fingeraftryk"</string>
+ <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingeroplåsning"</string>
<string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Fingeraftrykssensoren kan ikke bruges"</string>
<string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Få den repareret."</string>
<string name="face_acquired_insufficient" msgid="6889245852748492218">"Din ansigtsmodel kan ikke oprettes. Prøv igen."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 46268a625a62..a1064c297ebb 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -319,7 +319,7 @@
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"enregistrer des fichiers audio"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Activité physique"</string>
<string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"accéder à vos activités physiques"</string>
- <string name="permgrouplab_camera" msgid="9090413408963547706">"appareil photo"</string>
+ <string name="permgrouplab_camera" msgid="9090413408963547706">"Appareil photo"</string>
<string name="permgroupdesc_camera" msgid="7585150538459320326">"prendre des photos et filmer des vidéos"</string>
<string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Appareils à proximité"</string>
<string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"découvrir les appareils à proximité et s\'y connecter"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index eb4f2a705b78..b75fa4b22573 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -328,7 +328,7 @@
<string name="permgroupdesc_phone" msgid="270048070781478204">"ಫೋನ್ ಕರೆ ಮಾಡಲು ಹಾಗೂ ನಿರ್ವಹಿಸಲು"</string>
<string name="permgrouplab_sensors" msgid="9134046949784064495">"ಬಾಡಿ ಸೆನ್ಸರ್‌"</string>
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"ನಿಮ್ಮ ಮುಖ್ಯ ಲಕ್ಷಣಗಳ ಕುರಿತು ಸೆನ್ಸಾರ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
- <string name="permgrouplab_notifications" msgid="5472972361980668884">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="permgrouplab_notifications" msgid="5472972361980668884">"ನೋಟಿಫಿಕೇಶನ್‌ಗಳು"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ವಿಂಡೋ ವಿಷಯವನ್ನು ಹಿಂಪಡೆಯುತ್ತದೆ"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ನೀವು ಬಳಸುತ್ತಿರುವ ವಿಂಡೋದ ವಿಷಯ ಪರೀಕ್ಷಿಸುತ್ತದೆ."</string>
@@ -2130,7 +2130,7 @@
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"ಹೋಮ್"</string>
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"ಹಿಂದಕ್ಕೆ"</string>
<string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್‌ಗಳು"</string>
- <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"ನೋಟಿಫಿಕೇಶನ್‌ಗಳು"</string>
<string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು"</string>
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ಪವರ್ ಡೈಲಾಗ್"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 2934728c5b56..ee378dcff9cc 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -763,7 +763,7 @@
<string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"тармактын колдонулуш таржымалын окуу"</string>
<string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"Колдонмого белгилүү бир тармактарга жана колдонмолорго байланыштуу тармактын колдонулушу жөнүндө таржымалды окуу мүмкүнчүлүгүн берет."</string>
<string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"тармак саясатын башкаруу"</string>
- <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"Колдонмого тармак саясаттарын башкаруу жана колдонмого мүнөздүү эрежелерди белгилөө мүмкүнчүлүгүн берет."</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"Колдонмого тармак эрежелерин башкаруу жана колдонмого мүнөздүү эрежелерди белгилөө мүмкүнчүлүгүн берет."</string>
<string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"тармактын колдонулуш эсеп-кысабын өзгөртүү"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"Колдонмого желени башка колдонмолордун пайдалануусун башкарган тууралоолорду киргизүү уруксатын берет. Жөнөкөй колдонмолор үчүн эмес."</string>
<string name="permlab_accessNotifications" msgid="7130360248191984741">"эскертүүлөр менен иштөө"</string>
@@ -1716,7 +1716,7 @@
<string name="color_inversion_feature_name" msgid="2672824491933264951">"Түстөрдү инверсиялоо"</string>
<string name="color_correction_feature_name" msgid="7975133554160979214">"Түстөрдү тууралоо"</string>
<string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Бир кол режими"</string>
- <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дагы караңгы"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Кошумча караңгылатуу"</string>
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"Угуу түзмөктөрү"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> күйгүзүлдү."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өчүрүлдү."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 43d7a0b4431e..0ce7b1314e01 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -808,7 +808,7 @@
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Дэлгэц түгжигдсэн үед нууц үг буруу оруулалтын тоог хянах ба хэрэв хэт олон удаа нууц үгийг буруу оруулбал таблетыг түгжих болон таблетын бүх датаг арилгана"</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Дэлгэцийн түгжээг тайлахаар буруу оруулсан нууц үгийн тоог хянаж, нууц үгийг хэт олон удаа буруу оруулсан тохиолдолд таны Android TV төхөөрөмжийг түгжиж эсвэл үүний бүх өгөгдлийг устгана."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Дэлгэцийн түгжээг тайлахад буруу бичиж оруулсан нууц үгний тоог хянаж, инфотэйнмент системийг түгжих эсвэл хэт олон удаа нууц үгийг буруу бичиж оруулсан тохиолдолд инфотэйнмент системийн бүх өгөгдлийг устгана."</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Дэлгэц түгжигдсэн үед нууц үг буруу оруулалтын тоог хянах, ба хэрэв хэт олон удаа нууц үгийг буруу оруулбал утсыг түгжих болон утасны бүх датаг арилгана"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Дэлгэц түгжигдсэн үед нууц үг буруу оруулалтын тоог хянах, ба хэрэв хэт олон удаа нууц үгийг буруу оруулбал утсыг түгжиж эсвэл утасны бүх өгөгдлийг арилгана"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Дэлгэцийн түгжээг тайлахад оруулсан буруу нууц үгийн давтамжийг хянаж таблетыг түгжих эсвэл буруу нууц үгийг хэт олон удаа оруулсан тохиолдолд энэ хэрэглэгчийн мэдээллийг устгах."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Дэлгэцийн түгжээг тайлахаар буруу оруулсан нууц үгийн тоог хянаж, нууц үгийг хэт олон удаа буруу оруулсан тохиолдолд таны Android TV төхөөрөмжийг түгжиж эсвэл энэ хэрэглэгчийн бүх өгөгдлийг устгана."</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Дэлгэцийн түгжээг тайлахад буруу бичиж оруулсан нууц үгний тоог хянаж, инфотэйнмент системийг түгжих эсвэл хэт олон удаа нууц үгийг буруу бичиж оруулсан тохиолдолд энэ профайлын бүх өгөгдлийг устгана."</string>
@@ -817,11 +817,11 @@
<string name="policydesc_resetPassword" msgid="4626419138439341851">"Дэлгэцийн түгжээг өөрчлөх."</string>
<string name="policylab_forceLock" msgid="7360335502968476434">"Дэлгэц түгжих"</string>
<string name="policydesc_forceLock" msgid="1008844760853899693">"Дэлгэц хэзээ яаж түгжихийг удирдах"</string>
- <string name="policylab_wipeData" msgid="1359485247727537311">"Бүх датаг арилгах"</string>
+ <string name="policylab_wipeData" msgid="1359485247727537311">"Бүх өгөгдлийг арилгах"</string>
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Үйлдвэрийн дата утгыг өгсөнөөр таблетын дата шууд арилгагдана."</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Таны Android TV төхөөрөмжийн өгөгдлийг танд анхааруулалгүйгээр үйлдвэрээс гарсан төлөвт шилжүүлэн устгана."</string>
<string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Үйлдвэрийн өгөгдлийн төлөвт үйлдлийг гүйцэтгэснээр инфотэйнмент системийн өгөгдлийг сануулгагүйгээр устгана."</string>
- <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Сануулахгүйгээр утасны бүх мэдээллийг устгаж, үйлдвэрийн өгөгдмөл байдалд шилжүүлнэ"</string>
+ <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Сануулахгүйгээр утасны бүх өгөгдлийг арилгаж, үйлдвэрийн өгөгдлийн тохиргоонд шинэчилнэ"</string>
<string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"Профайлын өгөгдлийг устгах"</string>
<string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"Хэрэглэгчийн мэдээллийг арилгах"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Анхааруулга өгөхгүйгээр энэ хэрэглэгчийн энэ таблет дээрх мэдээллийг устгах."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index f39bdf4d9037..af07eaf05548 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2124,7 +2124,7 @@
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth akan kekal hidup semasa dalam mod pesawat"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Memuatkan"</string>
<string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fail}other{{file_name} + # fail}}"</string>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Tiada orang yang disyorkan untuk berkongsi"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Tiada orang yang disyorkan untuk membuat perkongsian"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Senarai apl"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Apl ini belum diberikan kebenaran merakam tetapi dapat merakam audio melalui peranti USB ini."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Skrin Utama"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 4ac0b2f5c882..d4f08e43f37a 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -808,7 +808,7 @@
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"မျက်နှာပြင်ကို သော့ဖွင့်ရန် အတွက် စကားဝှက် မမှန်မကန် ထည့်သွင်းမှု အရေအတွက်ကို စောင့်ကြည့်လျက်၊ စကားဝှက် ရိုက်ထည့်မှု သိပ်များနေလျှင် တက်ဘလက်ကို သော့ခတ်ရန် သို့မဟုတ် တက်ဘလက် ဒေတာ အားလုံးကို ဖျက်ရန်။"</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"မျက်နှာပြင်ကို လော့ခ်ဖွင့်သည့်အခါ စကားဝှက်မှားယွင်းစွာ ရိုက်သွင်းသည့်အကြိမ်ရေကို စောင့်ကြည့်ပြီး မှားယွင်းသည့်အကြိမ်ရေ အလွန်များလာပါက သင့် Android TV စက်ပစ္စည်းကို လော့ခ်ချခြင်း သို့မဟုတ် သင့် Android TV ရှိ အသုံးပြုသူဒေတာများအားလုံးကို ဖျက်ခြင်းတို့ ပြုလုပ်သွားပါမည်။"</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"ဖန်သားပြင်လော့ခ်ဖွင့်ရန် အတွက် စကားဝှက် မမှန်မကန် ထည့်သွင်းမှု အရေအတွက်ကို စောင့်ကြည့်လျက် စကားဝှက် မမှန်မကန် ရိုက်ထည့်မှု များနေလျှင် သတင်းနှင့်ဖျော်ဖြေရေး စနစ်ကို လော့ခ်ချသည် (သို့) ၎င်း၏ ဒေတာအားလုံးကို ဖျက်သည်။"</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"မျက်နှာပြင်ကို သော့ဖွင့်ရန် အတွက် စကားဝှက် မမှန်မကန် ထည့်သွင်းမှု အရေအတွက်ကို စောင့်ကြည့်လျက်၊ စကားဝှက် ရိုက်ထည့်မှု သိပ်များနေလျှင် ဖုန်းကို သော့ခတ်ရန် သို့မဟုတ် ဖုန်း ဒေတာ အားလုံးကို ဖျက်ရန်။"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"မျက်နှာပြင်ကို လောခ်ဖွင့်ရန်အတွက် ရိုက်ထည့်သည့် မှားယွင်းသောစကားဝှက် အကြိမ်ရေကို စောင့်ကြည့်ပြီး မမှန်သောစကားဝှက် ရိုက်ထည့်မှု အလွန်များနေလျှင် ဖုန်းကိုလော့ခ်ချသည် (သို့) ဖုန်း ဒေတာအားလုံးကို ဖျက်သည်။"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"ဖန်မျက်နှာပြင်အား သော့ဖွင့်စဉ် လျှို့ဝှက်ကုဒ်အမှားများ ရိုက်သွင်းမှုအား စောင့်ကြည့်ရန်နှင့်၊ လျှို့ဝှက်ကုဒ်အမှားများ များစွာ ရိုက်သွင်းပါက တက်ဘလက်အား သော့ချခြင်း သို့မဟုတ် တက်ဘလက်၏ အချက်အလက်များအား ဖျက်ပစ်ခြင်းများ ပြုလုပ်မည်။"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"မျက်နှာပြင်ကို လော့ခ်ဖွင့်သည့်အခါ စကားဝှက်မှားယွင်းစွာ ရိုက်သွင်းသည့်အကြိမ်ရေကို စောင့်ကြည့်ပြီး မှားယွင်းသည့်အကြိမ်ရေ အလွန်များလာပါက သင့် Android TV စက်ပစ္စည်းကို လော့ခ်ချခြင်း သို့မဟုတ် ဤအသုံးပြုသူဒေတာများအားလုံးကို ဖျက်ခြင်းတို့ ပြုလုပ်သွားပါမည်။"</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"ဖန်သားပြင်လော့ခ်ဖွင့်ရန် အတွက် စကားဝှက် မမှန်မကန် ထည့်သွင်းမှု အရေအတွက်ကို စောင့်ကြည့်လျက် စကားဝှက် မမှန်မကန် ရိုက်ထည့်မှု များနေလျှင် သတင်းနှင့်ဖျော်ဖြေရေး စနစ်ကို လော့ခ်ချသည် (သို့) ဤပရိုဖိုင်၏ ဒေတာအားလုံးကို ဖျက်သည်။"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 259744176ac0..62818b0e6736 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2295,7 +2295,7 @@
<string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"Blokkeren van apparaatmicrofoon opheffen"</string>
<string name="sensor_privacy_start_use_camera_notification_content_title" msgid="7287720213963466672">"Blokkeren van apparaatcamera opheffen"</string>
<string name="sensor_privacy_start_use_notification_content_text" msgid="7595608891015777346">"Voor &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; en alle andere apps en services"</string>
- <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7089318886628390827">"Blokkeren opheffen"</string>
+ <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7089318886628390827">"Niet meer blokkeren"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorprivacy"</string>
<string name="splash_screen_view_icon_description" msgid="180638751260598187">"App-icoon"</string>
<string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Merkafbeelding voor app"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index ae152f50932c..3c1776e95007 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2124,7 +2124,7 @@
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ ਵੇਲੇ ਬਲੂਟੁੱਥ ਹਾਲੇ ਵੀ ਚਾਲੂ ਹੋ ਜਾਵੇਗਾ"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # ਫ਼ਾਈਲ}one{{file_name} + # ਫ਼ਾਈਲ}other{{file_name} + # ਫ਼ਾਈਲਾਂ}}"</string>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ਸਾਂਝਾ ਕਰਨ ਲਈ ਕੋਈ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੇ ਲੋਕ ਨਹੀਂ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ਸਾਂਝਾ ਕਰਨ ਲਈ ਕੋਈ ਸਿਫ਼ਾਰਸ਼ ਕੀਤਾ ਵਿਅਕਤੀ ਨਹੀਂ ਹੈ"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"ਐਪ ਸੂਚੀ"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"ਇਸ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਪਰ ਇਹ USB ਡੀਵਾਈਸ ਰਾਹੀਂ ਆਡੀਓ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"ਹੋਮ"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ffa3d4d4bf23..1d7b124718bb 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1863,7 +1863,7 @@
<string name="select_day" msgid="2060371240117403147">"Выберите месяц и число"</string>
<string name="select_year" msgid="1868350712095595393">"Выберите год"</string>
<string name="deleted_key" msgid="9130083334943364001">"Цифра <xliff:g id="KEY">%1$s</xliff:g> удалена"</string>
- <string name="managed_profile_label_badge" msgid="6762559569999499495">"Рабочий <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="managed_profile_label_badge" msgid="6762559569999499495">"<xliff:g id="LABEL">%1$s</xliff:g> (рабочий профиль)"</string>
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Задача 2: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Задача 3: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="clone_profile_label_badge" msgid="1871997694718793964">"Клонировать <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 0104c899edfd..b05a861614be 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2157,9 +2157,9 @@
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Pamja personale"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Pamja e punës"</string>
<string name="resolver_cross_profile_blocked" msgid="3014597376026044840">"Bllokuar nga administratori yt i teknologjisë së informacionit"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Kjo përmbajtje nuk mund të shpërndahet me aplikacione pune"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Kjo përmbajtje nuk mund të ndahet me aplikacione pune"</string>
<string name="resolver_cant_access_work_apps_explanation" msgid="1129960195389373279">"Kjo përmbajtje nuk mund të hapet me aplikacione pune"</string>
- <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Kjo përmbajtje nuk mund të shpërndahet me aplikacione personale"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Kjo përmbajtje nuk mund të ndahet me aplikacione personale"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Kjo përmbajtje nuk mund të hapet me aplikacione personale"</string>
<string name="resolver_turn_on_work_apps" msgid="1535946298236678122">"Aplikacionet e punës janë vendosur në pauzë"</string>
<string name="resolver_switch_on_work" msgid="4527096360772311894">"Hiq nga pauza"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 91da16cbbeb9..da5c127fa512 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -805,7 +805,7 @@
<string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"Дозвољава власнику да ажурира апликацију коју је претходно инсталирала без радњи корисника"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Подешавање правила за лозинку"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Контролише дужину и знакове дозвољене у лозинкама и PIN-овима за закључавање екрана."</string>
- <string name="policylab_watchLogin" msgid="7599669460083719504">"Надгледајте покушаје откључавања екрана"</string>
+ <string name="policylab_watchLogin" msgid="7599669460083719504">"Надзор покушаја откључавања екрана"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Прати број нетачно унетих лозинки приликом откључавања екрана и закључава таблет или брише податке са таблета ако је нетачна лозинка унета превише пута."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава Android TV уређај или брише све податке са Android TV уређаја ако се унесе превише нетачних лозинки."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Прати број нетачно унетих лозинки при откључавању екрана и закључава систем за инфо-забаву или брише све податке са система за инфо-забаву ако је нетачна лозинка унета превише пута."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 37cbfc9837d7..6e999bdd8a45 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -322,7 +322,7 @@
<string name="permgroupdesc_camera" msgid="7585150538459320326">"చిత్రాలను తీయడానికి మరియు వీడియోను రికార్డ్ చేయడానికి"</string>
<string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"సమీపంలోని పరికరాలు"</string>
<string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"సమీప పరికరాలను కనుగొనండి అలాగే కనెక్ట్ చేయండి"</string>
- <string name="permgrouplab_calllog" msgid="7926834372073550288">"కాల్ లాగ్‌లు"</string>
+ <string name="permgrouplab_calllog" msgid="7926834372073550288">"కాల్ లాగ్స్‌"</string>
<string name="permgroupdesc_calllog" msgid="2026996642917801803">"ఫోన్ కాల్ లాగ్‌ని చదవండి మరియు రాయండి"</string>
<string name="permgrouplab_phone" msgid="570318944091926620">"ఫోన్"</string>
<string name="permgroupdesc_phone" msgid="270048070781478204">"ఫోన్ కాల్స్‌ చేయడం మరియు నిర్వహించడం"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 478b01cfa385..f5b0711a37aa 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -925,6 +925,9 @@
without impacting power, performance, and app compatibility (e.g. protected content). -->
<bool name="config_reduceBrightColorsAvailable">@bool/config_setColorTransformAccelerated</bool>
+ <!-- Whether to show Fold lock behavior setting feature in Settings App -->
+ <bool name="config_fold_lock_behavior">false</bool>
+
<string-array name="config_reduceBrightColorsCoefficientsNonlinear">
<!-- a-coefficient --> <item>-0.4429953456</item>
<!-- b-coefficient --> <item>-0.2434077725</item>
@@ -5615,13 +5618,13 @@
<!-- Blur radius for the Option 3 in R.integer.config_letterboxBackgroundType. Values < 0 are
ignored and 0 is used. -->
- <dimen name="config_letterboxBackgroundWallpaperBlurRadius">24dp</dimen>
+ <dimen name="config_letterboxBackgroundWallpaperBlurRadius">38dp</dimen>
<!-- Alpha of a black translucent scrim showed over wallpaper letterbox background when
the Option 3 is selected for R.integer.config_letterboxBackgroundType.
Values < 0 or >= 1 are ignored and 0.0 (transparent) is used instead. -->
<item name="config_letterboxBackgroundWallaperDarkScrimAlpha" format="float" type="dimen">
- 0.75
+ 0.54
</item>
<!-- Corners appearance of the letterbox background.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 644597c190dc..c78af86f0f39 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -343,6 +343,7 @@
<java-symbol type="string" name="config_defaultHealthConnectApp" />
<java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
<java-symbol type="bool" name="config_enableScreenshotChord" />
+ <java-symbol type="bool" name="config_fold_lock_behavior" />
<java-symbol type="bool" name="config_enableWifiDisplay" />
<java-symbol type="bool" name="config_allowAnimationsInLowPowerMode" />
<java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index c46118db617f..f39bddd7f032 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -88,8 +88,8 @@ public class HandwritingInitiatorTest {
}
private HandwritingInitiator mHandwritingInitiator;
- private View mTestView1;
- private View mTestView2;
+ private EditText mTestView1;
+ private EditText mTestView2;
private Context mContext;
@Before
@@ -123,6 +123,9 @@ public class HandwritingInitiatorTest {
@Test
public void onTouchEvent_startHandwriting_when_stylusMoveOnce_withinHWArea() {
+ mTestView1.setText("hello");
+ when(mTestView1.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(4);
+
mHandwritingInitiator.onInputConnectionCreated(mTestView1);
final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
@@ -141,6 +144,9 @@ public class HandwritingInitiatorTest {
// After IMM.startHandwriting is triggered, onTouchEvent should return true for ACTION_MOVE
// events so that the events are not dispatched to the view tree.
assertThat(onTouchEventResult2).isTrue();
+ // Since the stylus down point was inside the TextView's bounds, the handwriting initiator
+ // does not need to set the cursor position.
+ verify(mTestView1, never()).setSelection(anyInt());
}
@Test
@@ -185,6 +191,9 @@ public class HandwritingInitiatorTest {
@Test
public void onTouchEvent_startHandwriting_when_stylusMove_withinExtendedHWArea() {
+ mTestView1.setText("hello");
+ when(mTestView1.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(4);
+
mHandwritingInitiator.onInputConnectionCreated(mTestView1);
final int x1 = sHwArea1.left - HW_BOUNDS_OFFSETS_LEFT_PX / 2;
final int y1 = sHwArea1.top - HW_BOUNDS_OFFSETS_TOP_PX / 2;
@@ -199,6 +208,9 @@ public class HandwritingInitiatorTest {
// Stylus movement within extended HandwritingArea should trigger IMM.startHandwriting once.
verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView1);
+ // Since the stylus down point was outside the TextView's bounds, the handwriting initiator
+ // sets the cursor position.
+ verify(mTestView1).setSelection(4);
}
@Test
@@ -221,6 +233,8 @@ public class HandwritingInitiatorTest {
@Test
public void onTouchEvent_startHandwriting_inputConnectionBuilt_stylusMoveInExtendedHWArea() {
+ mTestView1.setText("hello");
+ when(mTestView1.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(4);
// The stylus down point is between mTestView1 and mTestView2, but it is within the
// extended handwriting area of both views. It is closer to mTestView1.
final int x1 = sHwArea1.right + HW_BOUNDS_OFFSETS_RIGHT_PX / 2;
@@ -241,6 +255,9 @@ public class HandwritingInitiatorTest {
// the stylus down point is closest to this view.
mHandwritingInitiator.onInputConnectionCreated(mTestView1);
verify(mHandwritingInitiator).startHandwriting(mTestView1);
+ // Since the stylus down point was outside the TextView's bounds, the handwriting initiator
+ // sets the cursor position.
+ verify(mTestView1).setSelection(4);
}
@Test
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
index b4c72ca3226b..3b2ab4c8bb50 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
@@ -16,6 +16,9 @@
package android.view.stylus;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -26,22 +29,23 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.EditText;
import androidx.test.platform.app.InstrumentationRegistry;
public class HandwritingTestUtil {
- public static View createView(Rect handwritingArea) {
+ public static EditText createView(Rect handwritingArea) {
return createView(handwritingArea, true /* autoHandwritingEnabled */,
true /* isStylusHandwritingAvailable */);
}
- public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled,
+ public static EditText createView(Rect handwritingArea, boolean autoHandwritingEnabled,
boolean isStylusHandwritingAvailable) {
return createView(handwritingArea, autoHandwritingEnabled, isStylusHandwritingAvailable,
0, 0, 0, 0);
}
- public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled,
+ public static EditText createView(Rect handwritingArea, boolean autoHandwritingEnabled,
boolean isStylusHandwritingAvailable,
float handwritingBoundsOffsetLeft, float handwritingBoundsOffsetTop,
float handwritingBoundsOffsetRight, float handwritingBoundsOffsetBottom) {
@@ -68,7 +72,7 @@ public class HandwritingTestUtil {
}
};
- View view = spy(new View(context));
+ EditText view = spy(new EditText(context));
when(view.isAttachedToWindow()).thenReturn(true);
when(view.isAggregatedVisible()).thenReturn(true);
when(view.isStylusHandwritingAvailable()).thenReturn(isStylusHandwritingAvailable);
@@ -77,6 +81,13 @@ public class HandwritingTestUtil {
when(view.getHandwritingBoundsOffsetTop()).thenReturn(handwritingBoundsOffsetTop);
when(view.getHandwritingBoundsOffsetRight()).thenReturn(handwritingBoundsOffsetRight);
when(view.getHandwritingBoundsOffsetBottom()).thenReturn(handwritingBoundsOffsetBottom);
+ doAnswer(invocation -> {
+ int[] outLocation = invocation.getArgument(0);
+ outLocation[0] = handwritingArea.left;
+ outLocation[1] = handwritingArea.top;
+ return null;
+ }).when(view).getLocationInWindow(any());
+ when(view.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(0);
view.setAutoHandwritingEnabled(autoHandwritingEnabled);
parent.addView(view);
return view;
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 71e9263915ee..16e94f8737d7 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1015,6 +1015,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
},
+ "-1152771606": {
+ "message": "Content Recording: Display %d was already recording, but pause capture since the task is in PIP",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"-1145384901": {
"message": "shouldWaitAnimatingExit: isTransition: %s",
"level": "DEBUG",
@@ -2323,6 +2329,12 @@
"group": "WM_DEBUG_SYNC_ENGINE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "1877956": {
+ "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"3593205": {
"message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
"level": "VERBOSE",
@@ -3055,6 +3067,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "643263584": {
+ "message": "Content Recording: Apply transformations of shift %d x %d, scale %f, crop %d x %d for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"644675193": {
"message": "Real start recents",
"level": "DEBUG",
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index eef363be387b..85ae1c10617c 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -76,10 +76,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Зразумела"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Няма нядаўніх усплывальных апавяшчэнняў"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Нядаўнія і адхіленыя ўсплывальныя апавяшчэнні будуць паказаны тут"</string>
- <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
- <skip />
- <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
- <skip />
+ <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Кіруйце наладамі ўсплывальных апавяшчэнняў у любы час"</string>
+ <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Каб кіраваць усплывальнымі апавяшчэннямі для праграм і размоў, націсніце тут"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Усплывальнае апавяшчэнне"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Кіраваць"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Усплывальнае апавяшчэнне адхілена."</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 54b1213ad216..2d5d371df41e 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -76,10 +76,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Եղավ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ամպիկներ չկան"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Այստեղ կցուցադրվեն վերջերս օգտագործված և փակված ամպիկները, որոնք կկարողանաք հեշտությամբ վերաբացել"</string>
- <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
- <skip />
- <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
- <skip />
+ <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Ամպիկների կարգավորումներ"</string>
+ <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Հպեք այստեղ՝ ընտրելու, թե որ հավելվածների և զրույցների համար ամպիկներ ցուցադրել"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Պղպջակ"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Կառավարել"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ամպիկը փակվեց։"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 0777abc087fa..0a0205d8f591 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -76,10 +76,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Đã hiểu"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Không có bong bóng trò chuyện nào gần đây"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Bong bóng trò chuyện đã đóng và bong bóng trò chuyện gần đây sẽ xuất hiện ở đây"</string>
- <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
- <skip />
- <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
- <skip />
+ <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kiểm soát bong bóng bất cứ lúc nào"</string>
+ <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Nhấn vào đây để quản lý việc dùng bong bóng cho các ứng dụng và cuộc trò chuyện"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bong bóng"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Quản lý"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Đã đóng bong bóng."</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index f272e91fe7a8..f93188343fdf 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -76,10 +76,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"我知道了"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近沒有任何對話框"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近的對話框和已關閉的對話框會顯示在這裡"</string>
- <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
- <skip />
- <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
- <skip />
+ <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"你隨時可以控管對話框的各項設定"</string>
+ <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"輕觸這裡即可管理哪些應用程式和對話可顯示對話框"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"泡泡"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已關閉泡泡。"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 9aac694e41bf..04795768aefc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -103,7 +103,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {}
/** Whether this task listener supports compat UI. */
default boolean supportCompatUI() {
- // All TaskListeners should support compat UI except PIP.
+ // All TaskListeners should support compat UI except PIP and StageCoordinator.
return true;
}
/** Attaches a child window surface to the task surface. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index 9b8006362c79..4640106b5f1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -245,8 +245,8 @@ class ActivityEmbeddingAnimationSpec {
private boolean shouldShowBackdrop(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change) {
- final Animation a = loadAttributeAnimation(info.getType(), info, change,
- WALLPAPER_TRANSITION_NONE, mTransitionAnimation, false);
+ final Animation a = loadAttributeAnimation(info, change, WALLPAPER_TRANSITION_NONE,
+ mTransitionAnimation, false);
return a != null && a.getShowBackdrop();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
index cbff4640239e..77aefc8f7e4a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
@@ -208,7 +208,7 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
}
private boolean getHasUserAspectRatioSettingsButton(@NonNull TaskInfo taskInfo) {
- return taskInfo.topActivityEligibleForUserAspectRatioButton
+ return taskInfo.topActivityEligibleForUserAspectRatioButton
&& (taskInfo.topActivityBoundsLetterboxed
|| taskInfo.isUserFullscreenOverrideEnabled);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 842b1bf9e8af..94fa485efd5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -228,6 +228,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private final Toast mSplitUnsupportedToast;
private SplitRequest mSplitRequest;
+ /**
+ * Since StageCoordinator only coordinates MainStage and SideStage, it shouldn't support
+ * CompatUI layouts. CompatUI is handled separately by MainStage and SideStage.
+ */
+ @Override
+ public boolean supportCompatUI() {
+ return false;
+ }
+
class SplitRequest {
@SplitPosition
int mActivatePosition;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index d310ae32993c..7df658e6c9db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -37,12 +37,8 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
-import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.window.TransitionInfo.FLAGS_IS_NON_APP_WINDOW;
import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL;
@@ -338,10 +334,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
boolean isDisplayRotationAnimationStarted = false;
final boolean isDreamTransition = isDreamTransition(info);
final boolean isOnlyTranslucent = isOnlyTranslucent(info);
- final boolean isActivityReplace = checkActivityReplacement(info, startTransaction);
- // Some patterns (eg. activity "replacement") require us to re-interpret the type
- @WindowManager.TransitionType final int transitType =
- isActivityReplace ? TRANSIT_OPEN : info.getType();
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -438,8 +430,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
// Don't animate anything that isn't independent.
if (!TransitionInfo.isIndependent(change, info)) continue;
- Animation a = loadAnimation(transitType, info, change, wallpaperTransit,
- isDreamTransition);
+ Animation a = loadAnimation(info, change, wallpaperTransit, isDreamTransition);
if (a != null) {
if (isTask) {
final boolean isTranslucent = (change.getFlags() & FLAG_TRANSLUCENT) != 0;
@@ -613,53 +604,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
return (translucentOpen + translucentClose) > 0;
}
- /**
- * Checks for an edge-case where an activity calls finish() followed immediately by
- * startActivity() to "replace" itself. If in this case, it will swap the layer of the
- * close/open activities and return `true`. This way, we pretend like we are just "opening"
- * the new activity.
- */
- private static boolean checkActivityReplacement(@NonNull TransitionInfo info,
- SurfaceControl.Transaction t) {
- if (info.getType() != TRANSIT_CLOSE) {
- return false;
- }
- int closing = -1;
- int opening = -1;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if ((change.getTaskInfo() != null || change.hasFlags(FLAG_IS_DISPLAY))
- && !TransitionUtil.isOrderOnly(change)) {
- // This isn't an activity-level transition.
- return false;
- }
- if (change.getTaskInfo() != null
- && change.hasFlags(FLAG_IS_DISPLAY | FLAGS_IS_NON_APP_WINDOW)) {
- // Ignore non-activity containers.
- continue;
- }
- if (TransitionUtil.isClosingType(change.getMode())) {
- closing = i;
- } else if (change.getMode() == TRANSIT_OPEN) {
- // OPEN implies that it is a new launch. If going "back" the opening app will be
- // TO_FRONT
- opening = i;
- } else if (change.getMode() == TRANSIT_TO_FRONT) {
- // Normal "going back", so not a replacement.
- return false;
- }
- }
- if (closing < 0 || opening < 0) {
- return false;
- }
- // Swap the opening and closing z-orders since we're swapping the transit type.
- final int numChanges = info.getChanges().size();
- final int zSplitLine = numChanges + 1;
- t.setLayer(info.getChanges().get(opening).getLeash(), zSplitLine + numChanges - opening);
- t.setLayer(info.getChanges().get(closing).getLeash(), zSplitLine - closing);
- return true;
- }
-
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@@ -712,11 +656,12 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
}
@Nullable
- private Animation loadAnimation(int type, @NonNull TransitionInfo info,
+ private Animation loadAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, int wallpaperTransit,
boolean isDreamTransition) {
Animation a;
+ final int type = info.getType();
final int flags = info.getFlags();
final int changeMode = change.getMode();
final int changeFlags = change.getFlags();
@@ -771,8 +716,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
// If there's a scene-transition, then jump-cut.
return null;
} else {
- a = loadAttributeAnimation(type, info, change, wallpaperTransit, mTransitionAnimation,
- isDreamTransition);
+ a = loadAttributeAnimation(
+ info, change, wallpaperTransit, mTransitionAnimation, isDreamTransition);
}
if (a != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index 7b1ce2fe6a08..d978eafa97f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -45,7 +45,6 @@ import android.graphics.Rect;
import android.graphics.Shader;
import android.view.Surface;
import android.view.SurfaceControl;
-import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.window.ScreenCapture;
@@ -62,10 +61,10 @@ public class TransitionAnimationHelper {
/** Loads the animation that is defined through attribute id for the given transition. */
@Nullable
- public static Animation loadAttributeAnimation(@WindowManager.TransitionType int type,
- @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
- int wallpaperTransit, @NonNull TransitionAnimation transitionAnimation,
- boolean isDreamTransition) {
+ public static Animation loadAttributeAnimation(@NonNull TransitionInfo info,
+ @NonNull TransitionInfo.Change change, int wallpaperTransit,
+ @NonNull TransitionAnimation transitionAnimation, boolean isDreamTransition) {
+ final int type = info.getType();
final int changeMode = change.getMode();
final int changeFlags = change.getFlags();
final boolean enter = TransitionUtil.isOpeningType(changeMode);
diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
index 89e48f96d27b..780274cc0a5b 100644
--- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
@@ -49,7 +49,7 @@
<string name="sign_ins" msgid="4710739369149469208">"prijavljivanja"</string>
<string name="sign_in_info" msgid="2627704710674232328">"podaci za prijavljivanje"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Sačuvaj <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> u"</string>
- <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Želite da napravite pristupni kôd na drugom uređaju?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Želite da napravite pristupni ključ na drugom uređaju?"</string>
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"Želite da sačuvate lozinku na drugom uređaju?"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Želite da sačuvate akreditive za prijavu na drugom uređaju?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite da za sva prijavljivanja koristite: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -72,7 +72,7 @@
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Želite da koristite sačuvanu lozinku za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Želite li da koristite svoje podatke za prijavljivanje za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Želite da otključate opcije prijavljivanja za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
- <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Izaberite sačuvan pristupni kôd za: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Izaberite sačuvan pristupni ključ za: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"Izaberite sačuvanu lozinku za: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Izaberite sačuvane podatke za prijavljivanje za: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"Odaberite podatke za prijavljivanje za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml
index e47cf7b2c75e..d6bf9463158f 100644
--- a/packages/CredentialManager/res/values-in/strings.xml
+++ b/packages/CredentialManager/res/values-in/strings.xml
@@ -54,7 +54,7 @@
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Simpan info login di perangkat lain?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gunakan <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> untuk semua info login Anda?"</string>
<string name="use_provider_for_all_description" msgid="1998772715863958997">"Pengelola sandi untuk <xliff:g id="USERNAME">%1$s</xliff:g> ini akan menyimpan sandi dan kunci sandi guna membantu Anda login dengan mudah"</string>
- <string name="set_as_default" msgid="4415328591568654603">"Setel sebagai default"</string>
+ <string name="set_as_default" msgid="4415328591568654603">"Jadikan default"</string>
<string name="settings" msgid="6536394145760913145">"Setelan"</string>
<string name="use_once" msgid="9027366575315399714">"Gunakan sekali"</string>
<string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> sandi • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> kunci sandi"</string>
diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml
index f5a29a212a61..b83c69816341 100644
--- a/packages/CredentialManager/res/values-sr/strings.xml
+++ b/packages/CredentialManager/res/values-sr/strings.xml
@@ -49,7 +49,7 @@
<string name="sign_ins" msgid="4710739369149469208">"пријављивања"</string>
<string name="sign_in_info" msgid="2627704710674232328">"подаци за пријављивање"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Сачувај <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> у"</string>
- <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Желите да направите приступни кôд на другом уређају?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Желите да направите приступни кључ на другом уређају?"</string>
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"Желите да сачувате лозинку на другом уређају?"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Желите да сачувате акредитиве за пријаву на другом уређају?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Желите да за сва пријављивања користите: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
@@ -72,7 +72,7 @@
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Желите да користите сачувану лозинку за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Желите ли да користите своје податке за пријављивање за апликацију <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Желите да откључате опције пријављивања за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
- <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Изаберите сачуван приступни кôд за: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Изаберите сачуван приступни кључ за: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"Изаберите сачувану лозинку за: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Изаберите сачуване податке за пријављивање за: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"Одаберите податке за пријављивање за апликацију <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index 90a723f707da..b77368a429ae 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -253,6 +253,7 @@ private fun SingleRowTopAppBar(
hideTitleSemantics = false,
navigationIcon = navigationIcon,
actions = actionsRow,
+ titleScaleDisabled = false,
)
}
}
@@ -426,6 +427,7 @@ private fun TwoRowsTopAppBar(
* accessibility services at the same time, when animating between collapsed / expanded states.
* @param navigationIcon a navigation icon [Composable]
* @param actions actions [Composable]
+ * @param titleScaleDisabled whether the title font scaling is disabled. Default is disabled.
*/
@Composable
private fun TopAppBarLayout(
@@ -443,6 +445,7 @@ private fun TopAppBarLayout(
hideTitleSemantics: Boolean,
navigationIcon: @Composable () -> Unit,
actions: @Composable () -> Unit,
+ titleScaleDisabled: Boolean = true,
) {
Layout(
{
@@ -466,9 +469,12 @@ private fun TopAppBarLayout(
ProvideTextStyle(value = titleTextStyle) {
CompositionLocalProvider(
LocalContentColor provides titleContentColor,
- // Disable the title font scaling by only passing the density but not the
- // font scale.
- LocalDensity provides Density(density = LocalDensity.current.density),
+ LocalDensity provides with(LocalDensity.current) {
+ Density(
+ density = density,
+ fontScale = if (titleScaleDisabled) 1f else fontScale,
+ )
+ },
content = title
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index 67f4418b7e4c..0a33b9bc6bc7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -18,6 +18,7 @@ package com.android.settingslib.spa.widget.scaffold
import androidx.activity.compose.BackHandler
import androidx.appcompat.R
+import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.RowScope
@@ -96,7 +97,8 @@ fun SearchScaffold(
Modifier
.padding(paddingValues.horizontalValues())
.padding(top = paddingValues.calculateTopPadding())
- .fillMaxSize(),
+ .focusable()
+ .fillMaxSize()
) {
content(
bottomPadding = paddingValues.calculateBottomPadding(),
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index e46db75f633e..33907ece5a7c 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -344,7 +344,9 @@ public class TileUtils {
continue;
}
final ProviderInfo providerInfo = resolved.providerInfo;
- final List<Bundle> entryData = getEntryDataFromProvider(context,
+ final List<Bundle> entryData = getEntryDataFromProvider(
+ // Build new context so the entry data is retrieved for the queried user.
+ context.createContextAsUser(user, 0 /* flags */),
providerInfo.authority);
if (entryData == null || entryData.isEmpty()) {
continue;
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index e9e0e90ed9dc..7472fff600fa 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -141,7 +141,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Otkaži"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Uparivanje omogućava pristup kontaktima i istoriji poziva nakon povezivanja."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Uparivanje sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije moguće."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Uparivanje sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije moguće zbog netačnog PIN-a ili pristupnog koda."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Uparivanje sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije moguće zbog netačnog PIN-a ili pristupnog ključa."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Nije moguće komunicirati sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> je odbio/la uparivanje"</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Računar"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index b037b134ac2a..8c83f6a39745 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -174,7 +174,7 @@
<string name="launch_defaults_some" msgid="3631650616557252926">"কিছু ডিফল্ট সেট করা রয়েছে"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"কোনও ডিফল্ট সেট করা নেই"</string>
<string name="tts_settings" msgid="8130616705989351312">"পাঠ্য থেকে ভাষ্য আউটপুট সেটিংস"</string>
- <string name="tts_settings_title" msgid="7602210956640483039">"টেক্সট-টু-স্পিচ"</string>
+ <string name="tts_settings_title" msgid="7602210956640483039">"টেক্সট-টু-স্পিচ আউটপুট"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"কথা বলার হার"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"যে গতিতে পাঠ্য উচ্চারিত হয়"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"পিচ"</string>
@@ -675,7 +675,7 @@
<string name="physical_keyboard_title" msgid="4811935435315835220">"ফিজিক্যাল কীবোর্ড"</string>
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"কীবোর্ড লেআউট বেছে নিন"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"ডিফল্ট"</string>
- <string name="turn_screen_on_title" msgid="3266937298097573424">"স্ক্রিন চালু করুন"</string>
+ <string name="turn_screen_on_title" msgid="3266937298097573424">"স্ক্রিন চালু করা"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"স্ক্রিন চালু করার অনুমতি দিন"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"অ্যাপকে স্ক্রিন চালু করার অনুমতি দিন। অনুমতি দেওয়া হলে, অ্যাপ আপনার এক্সপ্লিসিট ইনটেন্ট ছাড়াই যেকোনও সময় স্ক্রিন চালু করতে পারবে।"</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> সম্প্রচার বন্ধ করবেন?"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 233b3e1096b9..af13c2789d75 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -306,7 +306,7 @@
<string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quan aquest mode està activat, és possible que l’adreça MAC d\'aquest dispositiu canviï cada vegada que es connecti a una xarxa amb l\'aleatorització d\'adreces MAC activada"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"D\'ús mesurat"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"D\'ús no mesurat"</string>
- <string name="select_logd_size_title" msgid="1604578195914595173">"Mides de la memòria intermèdia del registrador"</string>
+ <string name="select_logd_size_title" msgid="1604578195914595173">"Mides de la memòria intermèdia del registre"</string>
<string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Selecciona la mida de la memòria intermèdia del registre"</string>
<string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"Vols esborrar l\'emmagatzematge persistent del registrador?"</string>
<string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"Quan deixem de supervisar amb el registrador persistent, hem d\'esborrar les dades del registrador que hi ha al teu dispositiu."</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index be847b308333..d13d022a1862 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -586,7 +586,7 @@
<string name="user_grant_admin_message" msgid="1673791931033486709">"Administraatoritel on eriõigused, mida teistel kasutajatel pole. Administraator saab hallata kõiki kasutajaid, värskendada või lähtestada seda seadet, muuta seadeid, vaadata kõiki installitud rakendusi ja anda teistele kasutajatele administraatoriõigused või need eemaldada."</string>
<string name="user_grant_admin_button" msgid="5441486731331725756">"Määra administraatoriks"</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Kas seadistada kasutaja kohe?"</string>
- <string name="user_setup_dialog_message" msgid="269931619868102841">"Veenduge, et isik saaks seadet kasutada ja oma ruumi seadistada"</string>
+ <string name="user_setup_dialog_message" msgid="269931619868102841">"Veenduge, et isik saaks seadet kasutada ja oma ruumi seadistada."</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Kas soovite kohe profiili seadistada?"</string>
<string name="user_setup_button_setup_now" msgid="1708269547187760639">"Seadista kohe"</string>
<string name="user_setup_button_setup_later" msgid="8712980133555493516">"Mitte praegu"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 07dd53ae320b..729e91f75e0b 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -599,7 +599,7 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Setel kunci"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Beralih ke <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Membuat pengguna baru …"</string>
- <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Membuat tamu baru …"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Membuat tamu baru…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Gagal membuat pengguna baru"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Gagal membuat tamu baru"</string>
<string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 818af41447d8..1c3053dc1ca4 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -580,7 +580,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"ಬಳಕೆದಾರ"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"ನಿರ್ಬಂಧಿಸಿದ ಪ್ರೊಫೈಲ್"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಬೇಕೆ?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"ನೀವು ಹೆಚ್ಚುವರಿ ಬಳಕೆದಾರರನ್ನು ರಚಿಸುವ ಮೂಲಕ ಇತರ ಜನರ ಜೊತೆಗೆ ಈ ಸಾಧನವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು. ಪ್ರತಿ ಬಳಕೆದಾರರು ತಮ್ಮದೇ ಸ್ಥಳವನ್ನು ಹೊಂದಿರುತ್ತಾರೆ, ಇದರಲ್ಲಿ ಅವರು ತಮ್ಮದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ವಾಲ್‌ಪೇಪರ್ ಮತ್ತು ಮುಂತಾದವುಗಳ ಮೂಲಕ ಕಸ್ಟಮೈಸ್ ಮಾಡಿಕೊಳ್ಳಬಹುದು. ಎಲ್ಲರ ಮೇಲೂ ಪರಿಣಾಮ ಬೀರುವಂತೆ ವೈ-ಫೈ ರೀತಿಯ ಸಾಧನ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬಳಕೆದಾರರು ಸರಿಹೊಂದಿಸಬಹುದು.\n\nನೀವು ಒಬ್ಬ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ತಮ್ಮ ಸ್ಥಳವನ್ನು ಸೆಟಪ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ.\n\nಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗೆ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಬಹುದು. ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಸೇವೆಗಳು ಹೊಸ ಬಳಕೆದಾರರಿಗೆ ವರ್ಗಾವಣೆ ಆಗದಿರಬಹುದು."</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"ನೀವು ಹೆಚ್ಚುವರಿ ಬಳಕೆದಾರರನ್ನು ರಚಿಸುವ ಮೂಲಕ ಇತರ ಜನರ ಜೊತೆಗೆ ಈ ಸಾಧನವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು. ಪ್ರತಿ ಬಳಕೆದಾರರು ತಮ್ಮದೇ ಸ್ಥಳವನ್ನು ಹೊಂದಿರುತ್ತಾರೆ, ಇದರಲ್ಲಿ ಅವರು ತಮ್ಮದೇ ಆ್ಯಪ್‌ಗಳು, ವಾಲ್‌ಪೇಪರ್ ಮತ್ತು ಮುಂತಾದವುಗಳ ಮೂಲಕ ಕಸ್ಟಮೈಸ್ ಮಾಡಿಕೊಳ್ಳಬಹುದು. ಎಲ್ಲರ ಮೇಲೂ ಪರಿಣಾಮ ಬೀರುವಂತೆ ವೈ-ಫೈ ರೀತಿಯ ಸಾಧನ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬಳಕೆದಾರರು ಸರಿಹೊಂದಿಸಬಹುದು.\n\nನೀವು ಒಬ್ಬ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ತಮ್ಮ ಸ್ಥಳವನ್ನು ಸೆಟಪ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ.\n\nಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗೆ ಆ್ಯಪ್‌ಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಬಹುದು. ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಸೇವೆಗಳು ಹೊಸ ಬಳಕೆದಾರರಿಗೆ ವರ್ಗಾವಣೆ ಆಗದಿರಬಹುದು."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"ನೀವು ಒಬ್ಬ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ತಮ್ಮ ಸ್ಥಳವನ್ನು ಸೆಟಪ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ.\n\nಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಬಹುದು."</string>
<string name="user_grant_admin_title" msgid="5157031020083343984">"ಈ ಬಳಕೆದಾರರನ್ನು ನಿರ್ವಾಹಕರನ್ನಾಗಿ ಮಾಡಬೇಕೆ?"</string>
<string name="user_grant_admin_message" msgid="1673791931033486709">"ನಿರ್ವಾಹಕರು ಇತರ ಬಳಕೆದಾರರಿಗೆ ಇಲ್ಲದ ವಿಶೇಷ ಸೌಲಭ್ಯಗಳನ್ನು ಹೊಂದಿದ್ದಾರೆ. ನಿರ್ವಾಹಕರು ಎಲ್ಲಾ ಬಳಕೆದಾರರನ್ನು ನಿರ್ವಹಿಸಬಹುದು, ಈ ಸಾಧನವನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಬಹುದು ಅಥವಾ ರೀಸೆಟ್ ಮಾಡಬಹುದು, ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಹೊಂದಿಸಬಹುದು, ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಎಲ್ಲಾ ಆ್ಯಪ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಬಹುದು ಮತ್ತು ಇತರರಿಗೆ ನಿರ್ವಾಹಕರಿಗೆ ನೀಡಿರುವ ಸೌಲಭ್ಯಗಳನ್ನು ನೀಡಬಹುದು ಅಥವಾ ಹಿಂತೆಗೆದುಕೊಳ್ಳಬಹುದು."</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 653ac2359cba..6b99e520c64a 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -581,7 +581,7 @@
<string name="user_add_profile_item_title" msgid="3111051717414643029">"제한된 프로필"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"신규 사용자를 추가할까요?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"추가 사용자를 만들어 다른 사용자와 기기를 공유할 수 있습니다. 각 사용자는 앱, 배경화면 등으로 맞춤설정할 수 있는 자신만의 공간을 갖게 됩니다. 또한 모든 사용자에게 영향을 미치는 Wi‑Fi와 같은 기기 설정도 조정할 수 있습니다.\n\n추가된 신규 사용자는 자신의 공간을 설정해야 합니다.\n\n모든 사용자가 앱을 업데이트할 수 있으며, 업데이트는 다른 사용자에게도 적용됩니다. 접근성 설정 및 서비스는 신규 사용자에게 이전되지 않을 수도 있습니다."</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"추가된 새로운 사용자는 자신의 공간을 설정해야 합니다.\n\n모든 사용자는 다른 사용자들을 위하여 앱을 업데이트할 수 있습니다."</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"추가된 신규 사용자는 자신의 공간을 설정해야 합니다.\n\n모든 사용자가 앱을 업데이트할 수 있으며, 업데이트는 다른 사용자에게도 적용됩니다."</string>
<string name="user_grant_admin_title" msgid="5157031020083343984">"이 사용자에게 관리자 권한을 부여하시겠습니까?"</string>
<string name="user_grant_admin_message" msgid="1673791931033486709">"관리자는 다른 사용자가 가지지 못한 특별한 권한을 보유합니다. 관리자는 모든 사용자를 관리하고, 기기를 업데이트하거나 재설정하고, 설정을 변경하고, 설치된 모든 앱을 확인하고, 다른 사용자에게 관리자 권한을 부여하거나 취소할 수 있습니다."</string>
<string name="user_grant_admin_button" msgid="5441486731331725756">"관리자 권한 부여"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index c2aa6520ae46..c1fc0f88ad98 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -351,10 +351,10 @@
<string name="debug_monitoring_category" msgid="1597387133765424994">"Мониторинг"</string>
<string name="strict_mode" msgid="889864762140862437">"Катаал режим иштетилди"</string>
<string name="strict_mode_summary" msgid="1838248687233554654">"Узак операцияларда экран күйүп-өчүп турат"</string>
- <string name="pointer_location" msgid="7516929526199520173">"Көрсөткүчтүн жайгшкн жери"</string>
+ <string name="pointer_location" msgid="7516929526199520173">"Көрсөткүчтүн турган жери"</string>
<string name="pointer_location_summary" msgid="957120116989798464">"Басылган жерлер жана жаңсоолор экранда көрүнүп турат"</string>
<string name="show_touches" msgid="8437666942161289025">"Басылган жерлерди көрсөтүү"</string>
- <string name="show_touches_summary" msgid="3692861665994502193">"Экранда басылган жерлер көрүнүп турат"</string>
+ <string name="show_touches_summary" msgid="3692861665994502193">"Экрандын басылган жерлери көрүнүп турат"</string>
<string name="show_key_presses" msgid="6360141722735900214">"Баскычтардын басылганын көрсөтүү"</string>
<string name="show_key_presses_summary" msgid="725387457373015024">"Баскычтар басылганда визуалдык сигнал көрүнөт"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Экран жаңыруусун көрсөтүү"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 29fb6d4b86c0..08ec8984254b 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -356,7 +356,7 @@
<string name="show_touches" msgid="8437666942161289025">"Товшилтыг харуулах"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Товшилтын визуал хариу үйлдлийг харуулах"</string>
<string name="show_key_presses" msgid="6360141722735900214">"Түлхүүрийн даралт харуул"</string>
- <string name="show_key_presses_summary" msgid="725387457373015024">"Биет түлхүүрийн даралтын визуал санал хүсэлт харуул"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Биет түлхүүрийн даралтын визуал хариу үйлдлийг харуул"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Гадаргын шинэчлэлтүүдийг харуулах"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Шинэчлэгдэх үед цонхны гадаргыг бүхэлд нь анивчуулах"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Шинэчлэлт харахыг харуулах"</string>
@@ -676,7 +676,7 @@
<string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Гарын бүдүүвчийг сонгох"</string>
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Өгөгдмөл"</string>
<string name="turn_screen_on_title" msgid="3266937298097573424">"Дэлгэцийг асаах"</string>
- <string name="allow_turn_screen_on" msgid="6194845766392742639">"Дэлгэцийг асаахыг зөвшөөрнө үү"</string>
+ <string name="allow_turn_screen_on" msgid="6194845766392742639">"Дэлгэцийг асаахыг зөвшөөрөх"</string>
<string name="allow_turn_screen_on_description" msgid="43834403291575164">"Аппад дэлгэцийг асаахыг зөвшөөрнө үү. Зөвшөөрсөн тохиолдолд тухайн апп таны тодорхой оролцоогүйгээр ямар ч үед дэлгэцийг асааж болно."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нэвтрүүлэхээ зогсоох уу?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Хэрэв та <xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлсэн эсвэл гаралтыг өөрчилсөн бол таны одоогийн нэвтрүүлэлтийг зогсооно"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 5d611329dd10..825f8b32e723 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -58,10 +58,10 @@
<string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\' मा जडान गर्न सकिँदैन"</string>
<string name="wifi_check_password_try_again" msgid="8817789642851605628">"पासवर्ड जाँच गरेर फेरि प्रयास गर्नुहोस्"</string>
<string name="wifi_not_in_range" msgid="1541760821805777772">"दायराभित्र छैन"</string>
- <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"स्वतः जडान हुने छैन"</string>
+ <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"अटो कनेक्ट हुने छैन"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"इन्टरनेटमाथिको पहुँच छैन"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा सेभ गरियो"</string>
- <string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s मार्फत् स्वतः जडान गरिएको"</string>
+ <string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s मार्फत् अटो कनेक्ट गरिएको"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"नेटवर्क मूल्याङ्कनकर्ता मार्फत स्वत: जडान गरिएको"</string>
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> मार्फत जडान गरिएको"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"साइन अप गर्न ट्याप गर्नुहोस्"</string>
@@ -581,7 +581,7 @@
<string name="user_add_profile_item_title" msgid="3111051717414643029">"प्रतिबन्धित प्रोफाइल"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"नयाँ प्रयोगकर्ता हाल्ने हो?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"तपाईं थप प्रयोगकर्ताहरू सिर्जना गरेर ती प्रयोगकर्तालाई यो डिभाइस प्रयोग गर्न दिन सक्नुहुन्छ। हरेक प्रयोगकर्ताको आफ्नै ठाउँ हुन्छ। उनीहरू यो ठाउँमा आफ्नै एप, वालपेपर आदिका लागि प्रयोग गर्न सक्छन्। उनीहरू सबैजनालाई असर पार्ने Wi-Fi जस्ता डिभाइसका सेटिङहरू पनि परिवर्तन गर्न सक्छन्।\n\nतपाईंले नयाँ प्रयोगकर्ता थप्दा उक्त व्यक्तिले आफ्नो ठाउँ सेटअप गर्नु पर्ने हुन्छ।\n\nसबै प्रयोगकर्ता अन्य सबै प्रयोगकर्ताले प्रयोग गर्ने एपहरू अद्यावधिक गर्न सक्छन्। तपाईं थप प्रयोगकर्ताहरू सिर्जना गरेर ती प्रयोगकर्तालाई यो डिभाइस प्रयोग गर्न दिन सक्नुहुन्छ। हरेक प्रयोगकर्ताको आफ्नै ठाउँ हुन्छ। उनीहरू यो ठाउँमा आफ्नै एप, वालपेपर आदिका लागि प्रयोग गर्न सक्छन्। उनीहरू सबैजनालाई असर पार्ने Wi-Fi जस्ता डिभाइसका सेटिङहरू पनि परिवर्तन गर्न सक्छन्।BREAK_0BREAK_1तपाईंले नयाँ प्रयोगकर्ता थप्दा उक्त व्यक्तिले आफ्नो ठाउँ सेटअप गर्नु पर्ने हुन्छ।BREAK_2BREAK_3सबै प्रयोगकर्ता अन्य सबै प्रयोगकर्ताले प्रयोग गर्ने एपहरू अद्यावधिक गर्न सक्छन्। तर पहुँचसम्बन्धी सेटिङ तथा सेवाहरू नयाँ प्रयोगकर्तामा नसर्न सक्छन्।"</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"तपाईंले नयाँ प्रयोगकर्ता थप्नुभयो भने ती प्रयोगकर्ताले आफ्नो स्पेस सेट गर्नु पर्ने हुन्छ।\n\nसबै प्रयोगकर्ताले अरू प्रयोगकर्ताका एपहरू अपडेट गर्न सक्छन्।"</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"तपाईंले नयाँ प्रयोगकर्ता हाल्नुभयो भने ती प्रयोगकर्ताले आफ्नो स्पेस सेट गर्नु पर्ने हुन्छ।\n\nसबै प्रयोगकर्ताले अरू प्रयोगकर्ताका एपहरू अपडेट गर्न सक्छन्।"</string>
<string name="user_grant_admin_title" msgid="5157031020083343984">"यी प्रयोगकर्तालाई एड्मिन बनाउने हो?"</string>
<string name="user_grant_admin_message" msgid="1673791931033486709">"एड्मिनहरूसँग अन्य प्रयोगकर्तासँग नभएका विशेषाधिकारहरू हुन्छन्। एड्मिन सबै प्रयोगकर्ताहरूलाई व्यवस्थापन गर्न, यो डिभाइस अपडेट वा रिसेट गर्न, सेटिङ परिमार्जन गर्न, इन्स्टल गरिएका सबै एपहरू हेर्न र अरूलाई एड्मिनका विशेषाधिकारहरू दिन वा अरूलाई दिइएका एड्मिनका विशेषाधिकारहरू खारेज गर्न सक्नुहुन्छ।"</string>
<string name="user_grant_admin_button" msgid="5441486731331725756">"एड्मिन बनाउनुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 48aa73579107..2ad1f48ad86b 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -382,7 +382,7 @@
<string name="show_non_rect_clip" msgid="7499758654867881817">"Depurar operações de clipe não retangulares"</string>
<string name="track_frame_time" msgid="522674651937771106">"Renderização HWUI do perfil"</string>
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Ativar cam. depuração GPU"</string>
- <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Permitir carregamento de camadas de depuração de GPU p/ apps de depuração"</string>
+ <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Permite carregamento de camadas de depuração de GPU para apps de depuração"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Ativ. registo do fornecedor"</string>
<string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Inclua registos adicionais de fornecedores específicos de dispositivos em relatórios de erros, que podem conter informações privadas, utilizar mais bateria e/ou utilizar mais armazenamento."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Escala de animação de transição"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 2fdac37e1dc8..a69ded5a5964 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -356,7 +356,7 @@
<string name="show_touches" msgid="8437666942161289025">"Shfaq trokitjet"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Shfaq reagimet vizuale për trokitjet"</string>
<string name="show_key_presses" msgid="6360141722735900214">"Shfaq shtypjet e tasteve"</string>
- <string name="show_key_presses_summary" msgid="725387457373015024">"Shfaq reagime vizuale për shtypjen e tasteve fizike"</string>
+ <string name="show_key_presses_summary" msgid="725387457373015024">"Shfaq reagim vizual për shtypjet fizike të tasteve"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Shfaq përditësimet e sipërfaqes"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Ndriço të gjitha sipërfaqet e dritares kur ato të përditësohen"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Shfaq përditësimet e pamjes"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index dc698ce037ec..ae466ce6aa42 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -141,7 +141,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Откажи"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Упаривање омогућава приступ контактима и историји позива након повезивања."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Упаривање са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g> није могуће."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Упаривање са <xliff:g id="DEVICE_NAME">%1$s</xliff:g> није могуће због нетачног PIN-а или приступног кода."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Упаривање са <xliff:g id="DEVICE_NAME">%1$s</xliff:g> није могуће због нетачног PIN-а или приступног кључа."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Није могуће комуницирати са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> је одбио/ла упаривање"</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Рачунар"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index bf297e66c9d8..b0489ab6f1ff 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -355,7 +355,7 @@
<string name="pointer_location_summary" msgid="957120116989798464">"Показувати на екрані жести й натискання"</string>
<string name="show_touches" msgid="8437666942161289025">"Показувати дотики"</string>
<string name="show_touches_summary" msgid="3692861665994502193">"Показувати візуальну реакцію на торкання"</string>
- <string name="show_key_presses" msgid="6360141722735900214">"Показувати натиск. клавіш"</string>
+ <string name="show_key_presses" msgid="6360141722735900214">"Показувати натискання клавіш"</string>
<string name="show_key_presses_summary" msgid="725387457373015024">"Показувати візуальний відгук на натискання клавіш"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Показ. оновлення поверхні"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Підсвічувати вікна повністю під час оновлення"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index ab16a731a570..a3e2838afa57 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -561,7 +561,7 @@
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
<string name="help_label" msgid="3528360748637781274">"帮助和反馈"</string>
- <string name="storage_category" msgid="2287342585424631813">"存储"</string>
+ <string name="storage_category" msgid="2287342585424631813">"存储空间"</string>
<string name="shared_data_title" msgid="1017034836800864953">"共享数据"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"查看和修改共享数据"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"此用户没有共享数据。"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index ceda9024eaa6..898fee23e0b2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -54,6 +54,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Stream;
/**
* CachedBluetoothDevice represents a remote Bluetooth device. It contains
@@ -652,6 +653,20 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
return mDevice.getBatteryLevel();
}
+ /**
+ * Get the lowest battery level from remote device and its member devices
+ * @return battery level in percentage [0-100] or
+ * {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
+ */
+ public int getMinBatteryLevelWithMemberDevices() {
+ return Stream.concat(Stream.of(this), mMemberDevices.stream())
+ .mapToInt(cachedDevice -> cachedDevice.getBatteryLevel())
+ .filter(batteryLevel -> batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
+ .min()
+ .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+ }
+
+
void refresh() {
ThreadUtils.postOnBackgroundThread(() -> {
if (BluetoothUtils.isAdvancedDetailsHeader(mDevice)) {
@@ -1147,7 +1162,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
// BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF, or BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
// any other value should be a framework bug. Thus assume here that if value is greater
// than BluetoothDevice.BATTERY_LEVEL_UNKNOWN, it must be valid
- final int batteryLevel = getBatteryLevel();
+ final int batteryLevel = getMinBatteryLevelWithMemberDevices();
if (batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
// TODO: name com.android.settingslib.bluetooth.Utils something different
batteryLevelPercentageString =
@@ -1322,7 +1337,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
// BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF, or BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
// any other value should be a framework bug. Thus assume here that if value is greater
// than BluetoothDevice.BATTERY_LEVEL_UNKNOWN, it must be valid
- final int batteryLevel = getBatteryLevel();
+ final int batteryLevel = getMinBatteryLevelWithMemberDevices();
if (batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
// TODO: name com.android.settingslib.bluetooth.Utils something different
batteryLevelPercentageString =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 4b61ff1177bd..85efe69529b4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -529,6 +529,51 @@ public class CachedBluetoothDeviceTest {
}
@Test
+ public void getConnectionSummary_testMemberDevicesExist_returnMinBattery() {
+ // One device is active with battery level 70.
+ mBatteryLevel = 70;
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
+
+
+ // Add a member device with battery level 30.
+ int lowerBatteryLevel = 30;
+ mCachedDevice.addMemberDevice(mSubCachedDevice);
+ doAnswer((invocation) -> lowerBatteryLevel).when(mSubCachedDevice).getBatteryLevel();
+
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 30% battery");
+ }
+
+ @Test
+ public void getConnectionSummary_testMemberDevicesBatteryUnknown_returnMinBattery() {
+ // One device is active with battery level 70.
+ mBatteryLevel = 70;
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
+
+ // Add a member device with battery level unknown.
+ mCachedDevice.addMemberDevice(mSubCachedDevice);
+ doAnswer((invocation) -> BluetoothDevice.BATTERY_LEVEL_UNKNOWN).when(
+ mSubCachedDevice).getBatteryLevel();
+
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 70% battery");
+ }
+
+ @Test
+ public void getConnectionSummary_testAllDevicesBatteryUnknown_returnNoBattery() {
+ // One device is active with battery level unknown.
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
+
+ // Add a member device with battery level unknown.
+ mCachedDevice.addMemberDevice(mSubCachedDevice);
+ doAnswer((invocation) -> BluetoothDevice.BATTERY_LEVEL_UNKNOWN).when(
+ mSubCachedDevice).getBatteryLevel();
+
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
+ }
+
+ @Test
public void getConnectionSummary_testMultipleProfilesActiveDevice() {
// Test without battery level
// Set A2DP and HFP profiles to be connected and test connection state summary
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 20864664e512..a8063e84cfca 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -35,6 +35,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -52,6 +53,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
@@ -69,6 +71,8 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.Arrays;
@@ -88,6 +92,10 @@ public class TileUtilsTest {
private UserManager mUserManager;
@Mock
private ContentResolver mContentResolver;
+ @Mock
+ private Context mUserContext;
+ @Mock
+ private ContentResolver mUserContentResolver;
private static final String URI_GET_SUMMARY = "content://authority/text/summary";
private static final String URI_GET_ICON = "content://authority/icon/my_icon";
@@ -104,6 +112,8 @@ public class TileUtilsTest {
mContentResolver = spy(application.getContentResolver());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getPackageName()).thenReturn("com.android.settings");
+ when(mUserContext.getContentResolver()).thenReturn(mUserContentResolver);
+ ShadowTileUtils.sCallRealEntryDataFromProvider = false;
}
@Test
@@ -375,6 +385,30 @@ public class TileUtilsTest {
}
@Test
+ public void loadTilesForAction_forUserProvider_getEntryDataFromProvider_inContextOfGivenUser() {
+ ShadowTileUtils.sCallRealEntryDataFromProvider = true;
+ UserHandle userHandle = new UserHandle(10);
+
+ doReturn(mUserContext).when(mContext).createContextAsUser(eq(userHandle), anyInt());
+
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+ URI_GET_SUMMARY, null, 123, PROFILE_ALL);
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
+
+ TileUtils.loadTilesForAction(mContext, userHandle, IA_SETTINGS_ACTION,
+ addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */);
+
+ verify(mUserContentResolver, atLeastOnce())
+ .acquireUnstableProvider(any(Uri.class));
+ }
+
+ @Test
public void loadTilesForAction_withPendingIntent_updatesPendingIntentMap() {
Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
List<Tile> outTiles = new ArrayList<>();
@@ -472,8 +506,17 @@ public class TileUtilsTest {
private static Bundle sMetaData;
+ private static boolean sCallRealEntryDataFromProvider;
+
@Implementation
protected static List<Bundle> getEntryDataFromProvider(Context context, String authority) {
+ if (sCallRealEntryDataFromProvider) {
+ return Shadow.directlyOn(
+ TileUtils.class,
+ "getEntryDataFromProvider",
+ ReflectionHelpers.ClassParameter.from(Context.class, context),
+ ReflectionHelpers.ClassParameter.from(String.class, authority));
+ }
return Arrays.asList(sMetaData);
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index c2dbf9813178..be6302141b0d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -241,6 +241,7 @@ public class SecureSettings {
Settings.Secure.HEARING_AID_MEDIA_ROUTING,
Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
- Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED
+ Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
+ Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 6b0a9060d782..248c60cb4fe9 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -61,7 +61,7 @@ public class SystemSettings {
Settings.System.TTY_MODE,
Settings.System.MASTER_MONO,
Settings.System.MASTER_BALANCE,
- Settings.System.STAY_AWAKE_ON_FOLD,
+ Settings.System.FOLD_LOCK_BEHAVIOR,
Settings.System.SOUND_EFFECTS_ENABLED,
Settings.System.HAPTIC_FEEDBACK_ENABLED,
Settings.System.POWER_SOUNDS_ENABLED, // moved to global
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index a49461e3a5af..ff32badf23fd 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -199,6 +199,7 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.ASSIST_TOUCH_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_LONG_PRESS_HOME_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.SEARCH_LONG_PRESS_HOME_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.VR_DISPLAY_MODE, new DiscreteValueValidator(new String[] {"0", "1"}));
VALIDATORS.put(Secure.NOTIFICATION_BADGING, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.NOTIFICATION_DISMISS_RTL, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index a08d07e1d778..3688d049d380 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -134,6 +134,7 @@ public class SystemSettingsValidators {
VALIDATORS.put(System.HAPTIC_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.RINGTONE, URI_VALIDATOR);
VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR);
+ VALIDATORS.put(System.FOLD_LOCK_BEHAVIOR, ANY_STRING_VALIDATOR);
VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR);
VALIDATORS.put(System.TEXT_AUTO_REPLACE, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.TEXT_AUTO_CAPS, BOOLEAN_VALIDATOR);
@@ -218,7 +219,6 @@ public class SystemSettingsValidators {
VALIDATORS.put(System.WIFI_STATIC_DNS1, LENIENT_IP_ADDRESS_VALIDATOR);
VALIDATORS.put(System.WIFI_STATIC_DNS2, LENIENT_IP_ADDRESS_VALIDATOR);
VALIDATORS.put(System.SHOW_BATTERY_PERCENT, BOOLEAN_VALIDATOR);
- VALIDATORS.put(System.STAY_AWAKE_ON_FOLD, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.CLOCKWORK_BLUETOOTH_SETTINGS_PREF, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ef4e84fcff7b..5c6729529fa8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1929,6 +1929,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
SecureSettingsProto.Assist.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED);
+ dumpSetting(s, p,
+ Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED,
+ SecureSettingsProto.Assist.SEARCH_LONG_PRESS_HOME_ENABLED);
p.end(assistToken);
final long assistHandlesToken = p.start(SecureSettingsProto.ASSIST_HANDLES);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index e3153e046a96..0a98032e26d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -94,6 +94,7 @@ final class SettingsState {
static final int SETTINGS_VERSION_NEW_ENCODING = 121;
+ public static final int MAX_LENGTH_PER_STRING = 32768;
private static final long WRITE_SETTINGS_DELAY_MILLIS = 200;
private static final long MAX_WRITE_SETTINGS_DELAY_MILLIS = 2000;
@@ -430,6 +431,19 @@ final class SettingsState {
return false;
}
+ final boolean isNameTooLong = name.length() > SettingsState.MAX_LENGTH_PER_STRING;
+ final boolean isValueTooLong =
+ value != null && value.length() > SettingsState.MAX_LENGTH_PER_STRING;
+ if (isNameTooLong || isValueTooLong) {
+ // only print the first few bytes of the name in case it is long
+ final String errorMessage = "The " + (isNameTooLong ? "name" : "value")
+ + " of your setting ["
+ + (name.length() > 20 ? (name.substring(0, 20) + "...") : name)
+ + "] is too long. The max length allowed for the string is "
+ + MAX_LENGTH_PER_STRING + ".";
+ throw new IllegalArgumentException(errorMessage);
+ }
+
Setting oldState = mSettings.get(name);
String oldValue = (oldState != null) ? oldState.value : null;
String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;
@@ -831,6 +845,7 @@ final class SettingsState {
private void doWriteState() {
boolean wroteState = false;
+ String settingFailedToBePersisted = null;
final int version;
final ArrayMap<String, Setting> settings;
final ArrayMap<String, String> namespaceBannedHashes;
@@ -860,7 +875,6 @@ final class SettingsState {
final int settingCount = settings.size();
for (int i = 0; i < settingCount; i++) {
-
Setting setting = settings.valueAt(i);
if (setting.isTransient()) {
if (DEBUG_PERSISTENCE) {
@@ -869,14 +883,27 @@ final class SettingsState {
continue;
}
- if (writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
- setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
- setting.getTag(), setting.isDefaultFromSystem(),
- setting.isValuePreservedInRestore())) {
- if (DEBUG_PERSISTENCE) {
- Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "="
- + setting.getValue());
+ try {
+ if (writeSingleSetting(mVersion, serializer, setting.getId(),
+ setting.getName(),
+ setting.getValue(), setting.getDefaultValue(),
+ setting.getPackageName(),
+ setting.getTag(), setting.isDefaultFromSystem(),
+ setting.isValuePreservedInRestore())) {
+ if (DEBUG_PERSISTENCE) {
+ Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "="
+ + setting.getValue());
+ }
}
+ } catch (IOException ex) {
+ Slog.e(LOG_TAG, "[ABORT PERSISTING]" + setting.getName()
+ + " due to error writing to disk", ex);
+ // A setting failed to be written. Abort the serialization to avoid leaving
+ // a partially serialized setting on disk, which can cause parsing errors.
+ // Note down the problematic setting, so that we can delete it before trying
+ // again to persist the rest of the settings.
+ settingFailedToBePersisted = setting.getName();
+ throw ex;
}
}
serializer.endTag(null, TAG_SETTINGS);
@@ -902,14 +929,14 @@ final class SettingsState {
Slog.i(LOG_TAG, "[PERSIST END]");
}
} catch (Throwable t) {
- Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t);
+ Slog.wtf(LOG_TAG, "Failed to write settings, restoring old file", t);
if (t instanceof IOException) {
- if (DEBUG) {
- // we failed to create a directory, so log the permissions and existence
- // state for the settings file and directory
- logSettingsDirectoryInformation(destination.getBaseFile());
- }
if (t.getMessage().contains("Couldn't create directory")) {
+ if (DEBUG) {
+ // we failed to create a directory, so log the permissions and existence
+ // state for the settings file and directory
+ logSettingsDirectoryInformation(destination.getBaseFile());
+ }
// attempt to create the directory with Files.createDirectories, which
// throws more informative errors than File.mkdirs.
Path parentPath = destination.getBaseFile().getParentFile().toPath();
@@ -930,7 +957,15 @@ final class SettingsState {
}
}
- if (wroteState) {
+ if (!wroteState) {
+ if (settingFailedToBePersisted != null) {
+ synchronized (mLock) {
+ // Delete the problematic setting. This will schedule a write as well.
+ deleteSettingLocked(settingFailedToBePersisted);
+ }
+ }
+ } else {
+ // success
synchronized (mLock) {
addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null);
}
@@ -1090,7 +1125,10 @@ final class SettingsState {
} catch (FileNotFoundException fnfe) {
final String message = "No fallback file found for: " + mStatePersistFile;
Slog.wtf(LOG_TAG, message);
- throw new IllegalStateException(message);
+ if (!isConfigSettingsKey(mKey)) {
+ // Allow partially deserialized config settings because they can be updated later
+ throw new IllegalStateException(message);
+ }
}
if (parseStateFromXmlStreamLocked(in)) {
// Parsed state from fallback file. Restore original file with fallback file
@@ -1102,7 +1140,10 @@ final class SettingsState {
} else {
final String message = "Failed parsing settings file: " + mStatePersistFile;
Slog.wtf(LOG_TAG, message);
- throw new IllegalStateException(message);
+ if (!isConfigSettingsKey(mKey)) {
+ // Allow partially deserialized config settings because they can be updated later
+ throw new IllegalStateException(message);
+ }
}
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 55160fbfd92e..26cac37f8b35 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -31,21 +31,21 @@ import java.io.PrintStream;
public class SettingsStateTest extends AndroidTestCase {
public static final String CRAZY_STRING =
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000b\u000c\r" +
- "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" +
- "\u001b\u001c\u001d\u001e\u001f\u0020" +
- "fake_setting_value_1" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
- "\u1000 \u2000 \u5000 \u8000 \uc000 \ue000" +
- "\ud800\udc00\udbff\udfff" + // surrogate pairs
- "\uD800ab\uDC00 " + // broken surrogate pairs
- "日本語";
+ "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" +
+ "\u001b\u001c\u001d\u001e\u001f\u0020" +
+ "fake_setting_value_1" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
+ "\u1000 \u2000 \u5000 \u8000 \uc000 \ue000" +
+ "\ud800\udc00\udbff\udfff" + // surrogate pairs
+ "\uD800ab\uDC00 " + // broken surrogate pairs
+ "日本語";
private static final String TEST_PACKAGE = "package";
private static final String SYSTEM_PACKAGE = "android";
@@ -170,11 +170,11 @@ public class SettingsStateTest extends AndroidTestCase {
final PrintStream os = new PrintStream(new FileOutputStream(file));
os.print(
"<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" +
- "<settings version=\"120\">" +
- " <setting id=\"0\" name=\"k0\" value=\"null\" package=\"null\" />" +
- " <setting id=\"1\" name=\"k1\" value=\"\" package=\"\" />" +
- " <setting id=\"2\" name=\"k2\" value=\"v2\" package=\"p2\" />" +
- "</settings>");
+ "<settings version=\"120\">" +
+ " <setting id=\"0\" name=\"k0\" value=\"null\" package=\"null\" />" +
+ " <setting id=\"1\" name=\"k1\" value=\"\" package=\"\" />" +
+ " <setting id=\"2\" name=\"k2\" value=\"v2\" package=\"p2\" />" +
+ "</settings>");
os.close();
final SettingsState ss = new SettingsState(getContext(), lock, file, 1,
@@ -408,4 +408,50 @@ public class SettingsStateTest extends AndroidTestCase {
}
assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
}
+
+ public void testLargeSettingKey() {
+ SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+ final String largeKey = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1);
+ final String testValue = "testValue";
+ synchronized (mLock) {
+ // Test system package
+ try {
+ settingsState.insertSettingLocked(largeKey, testValue, null, true, SYSTEM_PACKAGE);
+ fail("Should throw because it exceeded max string length");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+ }
+ // Test non system package
+ try {
+ settingsState.insertSettingLocked(largeKey, testValue, null, true, TEST_PACKAGE);
+ fail("Should throw because it exceeded max string length");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+ }
+ }
+ }
+
+ public void testLargeSettingValue() {
+ SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+ final String testKey = "testKey";
+ final String largeValue = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1);
+ synchronized (mLock) {
+ // Test system package
+ try {
+ settingsState.insertSettingLocked(testKey, largeValue, null, true, SYSTEM_PACKAGE);
+ fail("Should throw because it exceeded max string length");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+ }
+ // Test non system package
+ try {
+ settingsState.insertSettingLocked(testKey, largeValue, null, true, TEST_PACKAGE);
+ fail("Should throw because it exceeded max string length");
+ } catch (IllegalArgumentException ex) {
+ assertTrue(ex.getMessage().contains("The max length allowed for the string is "));
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index b708fc27448d..285fc5f1f332 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -6,6 +6,7 @@ dsandler@android.com
aaliomer@google.com
aaronjli@google.com
+achalke@google.com
acul@google.com
adamcohen@google.com
aioana@google.com
@@ -70,6 +71,7 @@ omarmt@google.com
patmanning@google.com
peanutbutter@google.com
peskal@google.com
+petrcermak@google.com
pinyaoting@google.com
pixel@google.com
pomini@google.com
@@ -81,13 +83,17 @@ santie@google.com
shanh@google.com
snoeberger@google.com
steell@google.com
+stevenckng@google.com
stwu@google.com
syeonlee@google.com
sunnygoyal@google.com
thiruram@google.com
+tkachenkoi@google.com
tracyzhou@google.com
tsuji@google.com
twickham@google.com
+vadimt@google.com
+vanjan@google.com
victortulias@google.com
winsonc@google.com
wleshner@google.com
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kn/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kn/strings.xml
index 5d1f722aee0c..0480a2e2e909 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-kn/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-kn/strings.xml
@@ -11,7 +11,7 @@
<string name="recent_apps_label" msgid="6583276995616385847">"ಇತ್ತೀಚಿನ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
<string name="lockscreen_label" msgid="648347953557887087">"ಲಾಕ್ ಸ್ಕ್ರೀನ್‌"</string>
<string name="quick_settings_label" msgid="2999117381487601865">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು"</string>
- <string name="notifications_label" msgid="6829741046963013567">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="notifications_label" msgid="6829741046963013567">"ನೋಟಿಫಿಕೇಶನ್‌ಗಳು"</string>
<string name="screenshot_label" msgid="863978141223970162">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
<string name="screenshot_utterance" msgid="1430760563401895074">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಿ"</string>
<string name="volume_up_label" msgid="8592766918780362870">"ವಾಲ್ಯೂಮ್ ಜಾಸ್ತಿ"</string>
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 764a8556a54d..a95ab5565ab9 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -24,6 +24,7 @@ import android.graphics.Matrix
import android.graphics.Path
import android.graphics.Rect
import android.graphics.RectF
+import android.os.Build
import android.os.Looper
import android.os.RemoteException
import android.util.Log
@@ -88,6 +89,9 @@ class ActivityLaunchAnimator(
contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f)
)
+ // TODO(b/288507023): Remove this flag.
+ @JvmField val DEBUG_LAUNCH_ANIMATION = Build.IS_DEBUGGABLE
+
private val DEFAULT_LAUNCH_ANIMATOR = LaunchAnimator(TIMINGS, INTERPOLATORS)
private val DEFAULT_DIALOG_TO_APP_ANIMATOR = LaunchAnimator(DIALOG_TIMINGS, INTERPOLATORS)
@@ -240,8 +244,17 @@ class ActivityLaunchAnimator(
private fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {
if (Looper.myLooper() != Looper.getMainLooper()) {
- this.launchContainer.context.mainExecutor.execute { this.onIntentStarted(willAnimate) }
+ this.launchContainer.context.mainExecutor.execute {
+ callOnIntentStartedOnMainThread(willAnimate)
+ }
} else {
+ if (DEBUG_LAUNCH_ANIMATION) {
+ Log.d(
+ TAG,
+ "Calling controller.onIntentStarted(willAnimate=$willAnimate) " +
+ "[controller=$this]"
+ )
+ }
this.onIntentStarted(willAnimate)
}
}
@@ -542,6 +555,13 @@ class ActivityLaunchAnimator(
Log.i(TAG, "Aborting the animation as no window is opening")
removeTimeout()
iCallback?.invoke()
+
+ if (DEBUG_LAUNCH_ANIMATION) {
+ Log.d(
+ TAG,
+ "Calling controller.onLaunchAnimationCancelled() [no window opening]"
+ )
+ }
controller.onLaunchAnimationCancelled()
return
}
@@ -759,6 +779,10 @@ class ActivityLaunchAnimator(
Log.i(TAG, "Remote animation timed out")
timedOut = true
+
+ if (DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [animation timed out]")
+ }
controller.onLaunchAnimationCancelled()
}
@@ -773,6 +797,13 @@ class ActivityLaunchAnimator(
removeTimeout()
animation?.cancel()
+
+ if (DEBUG_LAUNCH_ANIMATION) {
+ Log.d(
+ TAG,
+ "Calling controller.onLaunchAnimationCancelled() [remote animation cancelled]",
+ )
+ }
controller.onLaunchAnimationCancelled()
}
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 31df2baec08c..2d5796eedc78 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -303,7 +303,6 @@
-packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.kt
-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
diff --git a/packages/SystemUI/res/layout/media_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml
index e4749381243a..b77f78dfc644 100644
--- a/packages/SystemUI/res/layout/media_projection_app_selector.xml
+++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml
@@ -20,10 +20,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
- androidprv:maxCollapsedHeight="0dp"
+ androidprv:maxCollapsedHeight="10000dp"
androidprv:maxCollapsedHeightSmall="56dp"
androidprv:maxWidth="@*android:dimen/chooser_width"
android:id="@*android:id/contentPanel">
+ <!-- maxCollapsedHeight above is huge, to make sure the layout is always expanded. -->
<LinearLayout
android:id="@*android:id/chooser_header"
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 957e78559da2..9273a3a1fa6b 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -172,12 +172,12 @@
<string name="biometric_re_enroll_dialog_confirm" msgid="3049858021857801836">"Konfigurer"</string>
<string name="biometric_re_enroll_dialog_cancel" msgid="93760939407091417">"Ikke nu"</string>
<string name="biometric_re_enroll_notification_content" msgid="8685925877186288180">"Dette er påkrævet for at forbedre sikkerheden og ydeevnen"</string>
- <string name="fingerprint_re_enroll_notification_title" msgid="4539432429683916604">"Konfigurer oplåsning med fingeraftryk igen"</string>
- <string name="fingerprint_re_enroll_notification_name" msgid="630798657797645704">"Oplåsning med fingeraftryk"</string>
- <string name="fingerprint_re_enroll_dialog_title" msgid="3526033128113925780">"Konfigurer oplåsning med fingeraftryk"</string>
- <string name="fingerprint_re_enroll_dialog_content" msgid="4866561176695984879">"Hvis du vil konfigurere oplåsning med fingeraftryk igen, bliver dine nuværende fingeraftryksbilleder og -modeller slettet.\n\nNår de er slettet, skal du konfigurere oplåsning med fingeraftryk igen for at bruge dit fingeraftryk til at låse din telefon op eller verificere din identitet."</string>
- <string name="fingerprint_re_enroll_dialog_content_singular" msgid="3083663339787381218">"Hvis du vil konfigurere oplåsning med fingeraftryk igen, bliver dine nuværende fingeraftryksbilleder og -modeller slettet.\n\nNår de er slettet, skal du konfigurere oplåsning med fingeraftryk igen for at bruge dit fingeraftryk til at låse din telefon op eller verificere din identitet."</string>
- <string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"Oplåsning med fingeraftryk kunne ikke konfigureres. Gå til Indstillinger for at prøve igen."</string>
+ <string name="fingerprint_re_enroll_notification_title" msgid="4539432429683916604">"Konfigurer fingeroplåsning igen"</string>
+ <string name="fingerprint_re_enroll_notification_name" msgid="630798657797645704">"Fingeroplåsning"</string>
+ <string name="fingerprint_re_enroll_dialog_title" msgid="3526033128113925780">"Konfigurer fingeroplåsning"</string>
+ <string name="fingerprint_re_enroll_dialog_content" msgid="4866561176695984879">"Hvis du vil konfigurere fingeroplåsning igen, bliver dine nuværende fingeraftryksbilleder og -modeller slettet.\n\nNår de er slettet, skal du konfigurere fingeroplåsning igen for at bruge dit fingeraftryk til at låse din telefon op eller verificere din identitet."</string>
+ <string name="fingerprint_re_enroll_dialog_content_singular" msgid="3083663339787381218">"Hvis du vil konfigurere fingeroplåsning igen, bliver dine nuværende fingeraftryksbilleder og -modeller slettet.\n\nNår de er slettet, skal du konfigurere fingeroplåsning igen for at bruge dit fingeraftryk til at låse din telefon op eller verificere din identitet."</string>
+ <string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"Fingeroplåsning kunne ikke konfigureres. Gå til Indstillinger for at prøve igen."</string>
<string name="face_re_enroll_notification_title" msgid="1850838867718410520">"Konfigurer ansigtsoplåsning igen"</string>
<string name="face_re_enroll_notification_name" msgid="7384545252206120659">"Ansigtsoplåsning"</string>
<string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Konfigurer ansigtsoplåsning"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 409eac18453c..42c9e80c2c6e 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -254,7 +254,7 @@
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotazione automatica dello schermo"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Geolocalizzazione"</string>
<string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Salvaschermo"</string>
- <string name="quick_settings_camera_label" msgid="5612076679385269339">"Accesso alla fotocamera"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Accesso alla videocamera"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Accesso al microfono"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponibile"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloccato"</string>
@@ -1084,7 +1084,7 @@
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Aggiungi riquadro"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non aggiungerlo"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleziona utente"</string>
- <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{C\'è # app attiva}many{Ci sono # app attive}other{Ci sono # app attive}}"</string>
+ <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app è attiva}many{# di app sono attive}other{# app sono attive}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nuove informazioni"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"App attive"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Queste app sono attive e in esecuzione, anche quando non le utilizzi. Questo migliora la loro funzionalità, ma influisce sulla durata della batteria."</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 9549132974ed..85b95b1f4618 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -230,7 +230,7 @@
<string name="data_usage_disabled_dialog_mobile_title" msgid="2286843518689837719">"ಮೊಬೈಲ್ ಡೇಟಾವನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="data_usage_disabled_dialog_title" msgid="9131615296036724838">"ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="data_usage_disabled_dialog" msgid="7933201635215099780">"ಡೇಟಾ ಬಳಕೆಯು ನೀವು ಹೊಂದಿಸಿರುವ ಮಿತಿಯನ್ನು ತಲುಪಿದೆ. ಹೀಗಾಗಿ ನೀವು ಈಗ ಮೊಬೈಲ್ ಡೇಟಾ ಬಳಸುತ್ತಿಲ್ಲ.\n\nನೀವು ಮುಂದುವರಿದರೆ, ಡೇಟಾ ಬಳಕೆಗೆ ಶುಲ್ಕ ತೆರಬೇಕಾಗಬಹುದು."</string>
- <string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"ಮುಂದುವರಿಸು"</string>
+ <string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"ಮುಂದುವರಿಸಿ"</string>
<string name="accessibility_location_active" msgid="2845747916764660369">"ಸ್ಥಳ ವಿನಂತಿಗಳು ಸಕ್ರಿಯವಾಗಿವೆ"</string>
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"ಸೆನ್ಸರ್‌ಗಳು ಆಫ್ ಆಗಿವೆ"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೆರವುಗೊಳಿಸು."</string>
@@ -502,7 +502,7 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಮೇಲೆ ಸ್ವೈಪ್ ಮಾಡಿ ಮತ್ತು ಅನ್‌ಪಿನ್ ಮಾಡಲು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕನವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್‌ಪಿನ್ ಮಾಡಲು ಮುಖಪುಟವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿಹಿಡಿಯಿರಿ."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು (ಉದಾ, ಸಂಪರ್ಕಗಳು ಮತ್ತು ಇಮೇಲ್ ವಿಷಯ)."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಬಹುದು(ಉದಾ, ಸಂಪರ್ಕಗಳು ಮತ್ತು ಇಮೇಲ್ ಕಂಟೆಂಟ್‍)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ಪಿನ್ ಮಾಡಲಾದ ಆ್ಯಪ್ ಇತರ ಆ್ಯಪ್‌ಗಳನ್ನು ತೆರೆಯಬಹುದು."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್‌‌ಪಿನ್ ಮಾಡಲು, ಹಿಂದಕ್ಕೆ ಮತ್ತು ಸಮಗ್ರ ನೋಟ ಬಟನ್‌ಗಳನ್ನು ಸ್ಪರ್ಶಿಸಿ &amp; ಒತ್ತಿಹಿಡಿಯಿರಿ"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಲು, ಹಿಂದಕ್ಕೆ ಮತ್ತು ಮುಖಪುಟ ಬಟನ್‌ಗಳನ್ನು ಸ್ಪರ್ಶಿಸಿ &amp; ಒತ್ತಿಹಿಡಿಯಿರಿ"</string>
@@ -649,7 +649,7 @@
<string name="keyboard_shortcut_group_system_home" msgid="7465138628692109907">"ಮುಖಪುಟ"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="8628108256824616927">"ಇತ್ತೀಚಿನವುಗಳು"</string>
<string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"ಹಿಂದೆ"</string>
- <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"ನೋಟಿಫಿಕೇಶನ್‌ಗಳು"</string>
<string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
<string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ಕೀಬೋರ್ಡ್‌ ಲೇಔಟ್‌ ಬದಲಾಯಿಸಿ"</string>
<string name="keyboard_shortcut_clear_text" msgid="4679927133259287577">"ಪಠ್ಯ ತೆರವುಗೊಳಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings_tv.xml b/packages/SystemUI/res/values-kn/strings_tv.xml
index cfcc89642948..f1087aafd6c2 100644
--- a/packages/SystemUI/res/values-kn/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn/strings_tv.xml
@@ -22,7 +22,7 @@
<string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ಕನೆಕ್ಷನ್ ಕಡಿತಗೊಂಡಿದೆ"</string>
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ಮೂಲಕ"</string>
- <string name="tv_notification_panel_title" msgid="5311050946506276154">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="tv_notification_panel_title" msgid="5311050946506276154">"ನೋಟಿಫಿಕೇಶನ್‌ಗಳು"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ಯಾವುದೇ ಅಧಿಸೂಚನೆಗಳಿಲ್ಲ"</string>
<string name="mic_recording_announcement" msgid="7587123608060316575">"ಮೈಕ್ರೊಫೋನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
<string name="camera_recording_announcement" msgid="7240177719403759112">"ಕ್ಯಾಮರಾ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index e59c8f5c1035..fcbe6831b320 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -904,7 +904,7 @@
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# көзөмөл кошулду.}other{# көзөмөл кошулду.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Өчүрүлдү"</string>
<string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> кошулсунбу?"</string>
- <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> бул жерде көрсөтүлө турган башкаруу элементтерин жана контентти тандай алат."</string>
+ <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> бул жерде көрүнө турган нерселерди тандайт."</string>
<string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> башкаруу элементтери өчүрүлсүнбү?"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Сүйүктүүлөргө кошулду"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Сүйүктүүлөргө <xliff:g id="NUMBER">%d</xliff:g>-позицияга кошулду"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 8b58add1a270..b8f08f33af55 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -297,7 +297,7 @@
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ഔദ്യോഗിക ആപ്പുകൾ"</string>
<string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"തൽക്കാലം നിർത്തി"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"നൈറ്റ് ലൈറ്റ്"</string>
- <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"സൂര്യാസ്‌തമയത്തിന്"</string>
+ <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"അസ്‌തമയത്തിന്"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"സൂര്യോദയം വരെ"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> വരെ"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 1e4fbf5355cf..8fa29e01426d 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -99,7 +99,7 @@
<string name="screenrecord_title" msgid="4257171601439507792">"ဖန်သားပြင်ရိုက်ကူးစက်"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"စကရင်ရိုက်ကူးမှု အပြီးသတ်နေသည်"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ဖန်သားပြင် ရိုက်ကူးသည့် စက်ရှင်အတွက် ဆက်တိုက်လာနေသော အကြောင်းကြားချက်"</string>
- <string name="screenrecord_permission_dialog_title" msgid="303380743267672953">"စတင် ရိုက်သံဖမ်းမလား။"</string>
+ <string name="screenrecord_permission_dialog_title" msgid="303380743267672953">"ရိုက်သံဖမ်းခြင်း စတင်မလား။"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="4152602778470789965">"ရုပ်သံဖမ်းနေစဉ် Android သည် သင့်ဖန်သားပြင်တွင် မြင်နိုင်သည့် (သို့) သင့်စက်တွင် ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="6818309727772146138">"အက်ပ်တစ်ခုကို ရုပ်သံဖမ်းနေစဉ် Android သည် ယင်းအက်ပ်တွင် ပြထားသည့် (သို့) ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ ထို့ကြောင့် စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
<string name="screenrecord_permission_dialog_continue" msgid="5811122652514424967">"ရုပ်သံ စဖမ်းရန်"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 30f6efa0eff3..94d6c46fe580 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -297,13 +297,13 @@
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"कामसम्बन्धी एपहरू"</string>
<string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"पज गरिएको छ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Night Light"</string>
- <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"सूर्यास्तमा सक्रिय"</string>
+ <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"सर्यास्त हुँदा अन हुन्छ"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"सूर्योदयसम्म"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> मा सक्रिय"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> सम्म"</string>
<string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"अँध्यारो थिम"</string>
<string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"ब्याट्री सेभर"</string>
- <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"सूर्यास्तमा सक्रिय"</string>
+ <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"सर्यास्त हुँदा अन हुन्छ"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सूर्योदयसम्म"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> मा सक्रिय"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> सम्म"</string>
@@ -394,7 +394,7 @@
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"हो, जारी राख्नुहोस्"</string>
<string name="guest_notification_app_name" msgid="2110425506754205509">"अतिथि मोड"</string>
<string name="guest_notification_session_active" msgid="5567273684713471450">"तपाईं अतिथि मोड चलाउँदै हुनुहुन्छ"</string>
- <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"तपाईंले नयाँ प्रयोगकर्ता थप्नुभयो भने तपाईं अतिथि मोडबाट बाहिरिनु हुने छ र हालको अतिथि सत्रका सबै एप तथा डेटा मेटिने छ।"</string>
+ <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"तपाईंले नयाँ प्रयोगकर्ता हाल्नुभयो भने तपाईं अतिथि मोडबाट बाहिरिनु हुने छ र हालको अतिथि सत्रका सबै एप तथा डेटा मेटिने छ।"</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"प्रयोगकर्ताको सीमा पुग्यो"</string>
<string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{एउटा प्रोफाइल मात्र बनाउन सकिन्छ।}other{तपाईं बढीमा # जना प्रयोगकर्ता सामेल गराउन सक्नुहुन्छ।}}"</string>
<string name="user_remove_user_title" msgid="9124124694835811874">"प्रयोगकर्ता हटाउन चाहनुहुन्छ?"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 1d9b5fe2433c..93c82ebd6c65 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -297,7 +297,7 @@
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplikacionet e punës"</string>
<string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Vendosur në pauzë"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Drita e natës"</string>
- <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Në perëndim të diellit"</string>
+ <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Aktiv në perëndim"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Deri në lindje të diellit"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Aktive në <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Deri në <xliff:g id="TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 168ebf8bc4af..1037fa9106c1 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -752,7 +752,7 @@
<string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"вилучити опцію"</string>
<string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"додати опцію в кінець"</string>
<string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Перемістити опцію"</string>
- <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додати опцію"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додати панель"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Перемістити на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додати на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3ada7c2341ae..34b08b4433e2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1231,6 +1231,7 @@
<dimen name="magnification_setting_image_button_open_in_full_padding_horizontal">28dp</dimen>
<dimen name="magnification_setting_drag_corner_radius">28dp</dimen>
<dimen name="magnification_setting_drag_size">56dp</dimen>
+ <fraction name="magnification_resize_window_size_amount">10%</fraction>
<!-- Seekbar with icon buttons -->
<dimen name="seekbar_icon_size">24dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 9957429aaa6a..2fa895bb3e69 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -172,6 +172,10 @@
<item type="id" name="accessibility_action_move_right"/>
<item type="id" name="accessibility_action_move_up"/>
<item type="id" name="accessibility_action_move_down"/>
+ <item type="id" name="accessibility_action_increase_window_width"/>
+ <item type="id" name="accessibility_action_decrease_window_width"/>
+ <item type="id" name="accessibility_action_increase_window_height"/>
+ <item type="id" name="accessibility_action_decrease_window_height"/>
<!-- Accessibility actions for Accessibility floating menu. -->
<item type="id" name="action_move_top_left"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 275e5d8db153..3ca24afe6514 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2398,6 +2398,16 @@
<string name="accessibility_control_move_left">Move left</string>
<!-- Action in accessibility menu to move the magnification window right. [CHAR LIMIT=30] -->
<string name="accessibility_control_move_right">Move right</string>
+
+ <!-- Action in accessibility menu to increase the magnification window width. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_increase_window_width">Increase width of magnifier</string>
+ <!-- Action in accessibility menu to decrease the magnification window width. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_decrease_window_width">Decrease width of magnifier</string>
+ <!-- Action in accessibility menu to increase the magnification window height. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_increase_window_height">Increase height of magnifier</string>
+ <!-- Action in accessibility menu to decrease the magnification window height. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_control_decrease_window_height">Decrease height of magnifier</string>
+
<!-- Content description for magnification mode switch. [CHAR LIMIT=NONE] -->
<string name="magnification_mode_switch_description">Magnification switch</string>
<!-- A11y state description for magnification mode switch that device is in full-screen mode. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 28d59c21086b..c5887d392149 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -26,6 +26,7 @@ import static java.lang.Math.abs;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
@@ -703,6 +704,18 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
/**
+ * Sets the window frame size with given width and height in pixels without changing the
+ * window center.
+ *
+ * @param width the window frame width in pixels
+ * @param height the window frame height in pixels.
+ */
+ @MainThread
+ private void setMagnificationFrameSize(int width, int height) {
+ setWindowSize(width + 2 * mMirrorSurfaceMargin, height + 2 * mMirrorSurfaceMargin);
+ }
+
+ /**
* Sets the window size with given width and height in pixels without changing the
* window center. The width or the height will be clamped in the range
* [{@link #mMinWindowSize}, screen width or height].
@@ -1466,19 +1479,50 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
AccessibilityAction.ACTION_CLICK.getId(), getClickAccessibilityActionLabel());
info.addAction(clickAction);
info.setClickable(true);
+
info.addAction(
new AccessibilityAction(R.id.accessibility_action_zoom_in,
mContext.getString(R.string.accessibility_control_zoom_in)));
info.addAction(new AccessibilityAction(R.id.accessibility_action_zoom_out,
mContext.getString(R.string.accessibility_control_zoom_out)));
- info.addAction(new AccessibilityAction(R.id.accessibility_action_move_up,
- mContext.getString(R.string.accessibility_control_move_up)));
- info.addAction(new AccessibilityAction(R.id.accessibility_action_move_down,
- mContext.getString(R.string.accessibility_control_move_down)));
- info.addAction(new AccessibilityAction(R.id.accessibility_action_move_left,
- mContext.getString(R.string.accessibility_control_move_left)));
- info.addAction(new AccessibilityAction(R.id.accessibility_action_move_right,
- mContext.getString(R.string.accessibility_control_move_right)));
+
+ if (!mEditSizeEnable) {
+ info.addAction(new AccessibilityAction(R.id.accessibility_action_move_up,
+ mContext.getString(R.string.accessibility_control_move_up)));
+ info.addAction(new AccessibilityAction(R.id.accessibility_action_move_down,
+ mContext.getString(R.string.accessibility_control_move_down)));
+ info.addAction(new AccessibilityAction(R.id.accessibility_action_move_left,
+ mContext.getString(R.string.accessibility_control_move_left)));
+ info.addAction(new AccessibilityAction(R.id.accessibility_action_move_right,
+ mContext.getString(R.string.accessibility_control_move_right)));
+ } else {
+ if ((mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin)
+ < mWindowBounds.width()) {
+ info.addAction(new AccessibilityAction(
+ R.id.accessibility_action_increase_window_width,
+ mContext.getString(
+ R.string.accessibility_control_increase_window_width)));
+ }
+ if ((mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin)
+ < mWindowBounds.height()) {
+ info.addAction(new AccessibilityAction(
+ R.id.accessibility_action_increase_window_height,
+ mContext.getString(
+ R.string.accessibility_control_increase_window_height)));
+ }
+ if ((mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin) > mMinWindowSize) {
+ info.addAction(new AccessibilityAction(
+ R.id.accessibility_action_decrease_window_width,
+ mContext.getString(
+ R.string.accessibility_control_decrease_window_width)));
+ }
+ if ((mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin) > mMinWindowSize) {
+ info.addAction(new AccessibilityAction(
+ R.id.accessibility_action_decrease_window_height,
+ mContext.getString(
+ R.string.accessibility_control_decrease_window_height)));
+ }
+ }
info.setContentDescription(mContext.getString(R.string.magnification_window_title));
info.setStateDescription(formatStateDescription(getScale()));
@@ -1493,6 +1537,11 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
private boolean performA11yAction(int action) {
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+
if (action == AccessibilityAction.ACTION_CLICK.getId()) {
if (mEditSizeEnable) {
// When edit mode is enabled, click the magnifier to exit edit mode.
@@ -1514,9 +1563,26 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
move(-mSourceBounds.width(), 0);
} else if (action == R.id.accessibility_action_move_right) {
move(mSourceBounds.width(), 0);
+ } else if (action == R.id.accessibility_action_increase_window_width) {
+ int newFrameWidth =
+ (int) (mMagnificationFrame.width() * (1 + changeWindowSizeAmount));
+ setMagnificationFrameSize(newFrameWidth, mMagnificationFrame.height());
+ } else if (action == R.id.accessibility_action_increase_window_height) {
+ int newFrameHeight =
+ (int) (mMagnificationFrame.height() * (1 + changeWindowSizeAmount));
+ setMagnificationFrameSize(mMagnificationFrame.width(), newFrameHeight);
+ } else if (action == R.id.accessibility_action_decrease_window_width) {
+ int newFrameWidth =
+ (int) (mMagnificationFrame.width() * (1 - changeWindowSizeAmount));
+ setMagnificationFrameSize(newFrameWidth, mMagnificationFrame.height());
+ } else if (action == R.id.accessibility_action_decrease_window_height) {
+ int newFrameHeight =
+ (int) (mMagnificationFrame.height() * (1 - changeWindowSizeAmount));
+ setMagnificationFrameSize(mMagnificationFrame.width(), newFrameHeight);
} else {
return false;
}
+
mWindowMagnifierCallback.onAccessibilityActionPerformed(mDisplayId);
return true;
}
@@ -1527,4 +1593,5 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mDisplayId, scale, /* updatePersistence= */ true);
}
}
+
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index daff5feb0123..aa33100a3abe 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -16,13 +16,19 @@
package com.android.systemui.biometrics.data.repository
+import android.Manifest.permission.USE_BIOMETRIC_INTERNAL
+import android.annotation.RequiresPermission
+import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.biometrics.SensorProperties
import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.biometrics.shared.model.toSensorStrength
+import com.android.systemui.biometrics.shared.model.toSensorType
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
@@ -31,11 +37,10 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
/**
* A repository for the global state of FingerprintProperty.
@@ -44,22 +49,17 @@ import kotlinx.coroutines.flow.shareIn
*/
interface FingerprintPropertyRepository {
- /**
- * If the repository is initialized or not. Other properties are defaults until this is true.
- */
- val isInitialized: Flow<Boolean>
-
/** The id of fingerprint sensor. */
- val sensorId: StateFlow<Int>
+ val sensorId: Flow<Int>
/** The security strength of sensor (convenience, weak, strong). */
- val strength: StateFlow<SensorStrength>
+ val strength: Flow<SensorStrength>
/** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */
- val sensorType: StateFlow<FingerprintSensorType>
+ val sensorType: Flow<FingerprintSensorType>
/** The sensor location relative to each physical display. */
- val sensorLocations: StateFlow<Map<String, SensorLocationInternal>>
+ val sensorLocations: Flow<Map<String, SensorLocationInternal>>
}
@SysUISingleton
@@ -70,64 +70,64 @@ constructor(
private val fingerprintManager: FingerprintManager?,
) : FingerprintPropertyRepository {
- override val isInitialized: Flow<Boolean> =
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ private val props: StateFlow<FingerprintSensorPropertiesInternal> =
conflatedCallbackFlow {
val callback =
object : IFingerprintAuthenticatorsRegisteredCallback.Stub() {
override fun onAllAuthenticatorsRegistered(
sensors: List<FingerprintSensorPropertiesInternal>
) {
- if (sensors.isNotEmpty()) {
- setProperties(sensors[0])
- trySendWithFailureLogging(true, TAG, "initialize properties")
+ if (sensors.isEmpty()) {
+ trySendWithFailureLogging(
+ DEFAULT_PROPS,
+ TAG,
+ "no registered sensors, use default props"
+ )
+ } else {
+ trySendWithFailureLogging(
+ sensors[0],
+ TAG,
+ "update properties on authenticators registered"
+ )
}
}
}
fingerprintManager?.addAuthenticatorsRegisteredCallback(callback)
- trySendWithFailureLogging(false, TAG, "initial value defaulting to false")
awaitClose {}
}
- .shareIn(scope = applicationScope, started = SharingStarted.Eagerly, replay = 1)
-
- private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
- override val sensorId: StateFlow<Int> = _sensorId.asStateFlow()
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = DEFAULT_PROPS,
+ )
- private val _strength: MutableStateFlow<SensorStrength> =
- MutableStateFlow(SensorStrength.CONVENIENCE)
- override val strength = _strength.asStateFlow()
+ override val sensorId: Flow<Int> = props.map { it.sensorId }
- private val _sensorType: MutableStateFlow<FingerprintSensorType> =
- MutableStateFlow(FingerprintSensorType.UNKNOWN)
- override val sensorType = _sensorType.asStateFlow()
+ override val strength: Flow<SensorStrength> = props.map { it.sensorStrength.toSensorStrength() }
- private val _sensorLocations: MutableStateFlow<Map<String, SensorLocationInternal>> =
- MutableStateFlow(mapOf("" to SensorLocationInternal.DEFAULT))
- override val sensorLocations: StateFlow<Map<String, SensorLocationInternal>> =
- _sensorLocations.asStateFlow()
+ override val sensorType: Flow<FingerprintSensorType> =
+ props.map { it.sensorType.toSensorType() }
- private fun setProperties(prop: FingerprintSensorPropertiesInternal) {
- _sensorId.value = prop.sensorId
- _strength.value = prop.sensorStrength.toSensorStrength()
- _sensorType.value = sensorTypeIntToObject(prop.sensorType)
- _sensorLocations.value =
- prop.allLocations.associateBy { sensorLocationInternal ->
+ override val sensorLocations: Flow<Map<String, SensorLocationInternal>> =
+ props.map {
+ it.allLocations.associateBy { sensorLocationInternal ->
sensorLocationInternal.displayId
}
- }
+ }
companion object {
private const val TAG = "FingerprintPropertyRepositoryImpl"
- }
-}
-
-private fun sensorTypeIntToObject(value: Int): FingerprintSensorType {
- return when (value) {
- 0 -> FingerprintSensorType.UNKNOWN
- 1 -> FingerprintSensorType.REAR
- 2 -> FingerprintSensorType.UDFPS_ULTRASONIC
- 3 -> FingerprintSensorType.UDFPS_OPTICAL
- 4 -> FingerprintSensorType.POWER_BUTTON
- 5 -> FingerprintSensorType.HOME_BUTTON
- else -> throw IllegalArgumentException("Invalid SensorType value: $value")
+ private val DEFAULT_PROPS =
+ FingerprintSensorPropertiesInternal(
+ -1 /* sensorId */,
+ SensorProperties.STRENGTH_CONVENIENCE,
+ 0 /* maxEnrollmentsPerUser */,
+ listOf<ComponentInfoInternal>(),
+ FingerprintSensorProperties.TYPE_UNKNOWN,
+ false /* halControlsIllumination */,
+ true /* resetLockoutRequiresHardwareAuthToken */,
+ listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT)
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index 5badcaf06003..a6ad24e47edb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -32,7 +32,6 @@ import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -69,7 +68,7 @@ interface PromptSelectorInteractor {
val isConfirmationRequired: Flow<Boolean>
/** Fingerprint sensor type */
- val sensorType: StateFlow<FingerprintSensorType>
+ val sensorType: Flow<FingerprintSensorType>
/** Use biometrics for authentication. */
fun useBiometricsForAuthentication(
@@ -95,7 +94,7 @@ interface PromptSelectorInteractor {
class PromptSelectorInteractorImpl
@Inject
constructor(
- private val fingerprintPropertyRepository: FingerprintPropertyRepository,
+ fingerprintPropertyRepository: FingerprintPropertyRepository,
private val promptRepository: PromptRepository,
lockPatternUtils: LockPatternUtils,
) : PromptSelectorInteractor {
@@ -147,8 +146,7 @@ constructor(
}
}
- override val sensorType: StateFlow<FingerprintSensorType> =
- fingerprintPropertyRepository.sensorType
+ override val sensorType: Flow<FingerprintSensorType> = fingerprintPropertyRepository.sensorType
override fun useBiometricsForAuthentication(
promptInfo: PromptInfo,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt
index aa85e5f3b21a..75ae061f8cce 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt
@@ -17,32 +17,43 @@
package com.android.systemui.biometrics.domain.interactor
import android.hardware.biometrics.SensorLocationInternal
-import android.util.Log
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
/** Business logic for SideFps overlay offsets. */
interface SideFpsOverlayInteractor {
- /** Get the corresponding offsets based on different displayId. */
- fun getOverlayOffsets(displayId: String): SensorLocationInternal
+ /** The displayId of the current display. */
+ val displayId: Flow<String>
+
+ /** Overlay offsets corresponding to given displayId. */
+ val overlayOffsets: Flow<SensorLocationInternal>
+
+ /** Called on display changes, used to keep the display state in sync */
+ fun onDisplayChanged(displayId: String)
}
@SysUISingleton
class SideFpsOverlayInteractorImpl
@Inject
-constructor(private val fingerprintPropertyRepository: FingerprintPropertyRepository) :
+constructor(fingerprintPropertyRepository: FingerprintPropertyRepository) :
SideFpsOverlayInteractor {
- override fun getOverlayOffsets(displayId: String): SensorLocationInternal {
- val offsets = fingerprintPropertyRepository.sensorLocations.value
- return if (offsets.containsKey(displayId)) {
- offsets[displayId]!!
- } else {
- Log.w(TAG, "No location specified for display: $displayId")
- offsets[""]!!
+ private val _displayId: MutableStateFlow<String> = MutableStateFlow("")
+ override val displayId: Flow<String> = _displayId.asStateFlow()
+
+ override val overlayOffsets: Flow<SensorLocationInternal> =
+ combine(displayId, fingerprintPropertyRepository.sensorLocations) { displayId, offsets ->
+ offsets[displayId] ?: SensorLocationInternal.DEFAULT
}
+
+ override fun onDisplayChanged(displayId: String) {
+ _displayId.value = displayId
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
index df5cefdb876d..c6fdcb318998 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
@@ -27,3 +27,15 @@ enum class FingerprintSensorType {
POWER_BUTTON,
HOME_BUTTON,
}
+
+/** Convert [this] to corresponding [FingerprintSensorType] */
+fun Int.toSensorType(): FingerprintSensorType =
+ when (this) {
+ FingerprintSensorProperties.TYPE_UNKNOWN -> FingerprintSensorType.UNKNOWN
+ FingerprintSensorProperties.TYPE_REAR -> FingerprintSensorType.REAR
+ FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC -> FingerprintSensorType.UDFPS_ULTRASONIC
+ FingerprintSensorProperties.TYPE_UDFPS_OPTICAL -> FingerprintSensorType.UDFPS_OPTICAL
+ FingerprintSensorProperties.TYPE_POWER_BUTTON -> FingerprintSensorType.POWER_BUTTON
+ FingerprintSensorProperties.TYPE_HOME_BUTTON -> FingerprintSensorType.HOME_BUTTON
+ else -> throw IllegalArgumentException("Invalid SensorType value: $this")
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
index 30e865eff8b8..476daac5ff00 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
@@ -28,8 +28,8 @@ enum class SensorStrength {
/** Convert [this] to corresponding [SensorStrength] */
fun Int.toSensorStrength(): SensorStrength =
when (this) {
- 0 -> SensorStrength.CONVENIENCE
- 1 -> SensorStrength.WEAK
- 2 -> SensorStrength.STRONG
+ SensorProperties.STRENGTH_CONVENIENCE -> SensorStrength.CONVENIENCE
+ SensorProperties.STRENGTH_WEAK -> SensorStrength.WEAK
+ SensorProperties.STRENGTH_STRONG -> SensorStrength.STRONG
else -> throw IllegalArgumentException("Invalid SensorStrength value: $this")
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
index 9b30acb84428..b406ea41eff0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
@@ -33,7 +33,7 @@ class PromptFingerprintIconViewModel
@Inject
constructor(
private val displayStateInteractor: DisplayStateInteractor,
- private val promptSelectorInteractor: PromptSelectorInteractor,
+ promptSelectorInteractor: PromptSelectorInteractor,
) {
/** Current device rotation. */
private var rotation: Int = Surface.ROTATION_0
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 0dcba50df4ca..ef0f4941d4cd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -29,6 +29,7 @@ import android.app.IWallpaperManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.StatsManager;
+import android.app.StatusBarManager;
import android.app.UiModeManager;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
@@ -680,4 +681,10 @@ public class FrameworkServicesModule {
static TextClassificationManager provideTextClassificationManager(Context context) {
return context.getSystemService(TextClassificationManager.class);
}
+
+ @Provides
+ @Singleton
+ static StatusBarManager provideStatusBarManager(Context context) {
+ return context.getSystemService(StatusBarManager.class);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 5a2c5d08bc2e..b6c50f7603c7 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -112,14 +112,14 @@ object Flags {
val BUILDER_EXTRAS_OVERRIDE =
sysPropBooleanFlag(
"persist.sysui.notification.builder_extras_override",
- default = true
+ default = false
)
/** Only notify group expansion listeners when a change happens. */
// TODO(b/292213543): Tracking Bug
@JvmField
val NOTIFICATION_GROUP_EXPANSION_CHANGE =
- unreleasedFlag("notification_group_expansion_change", teamfood = true)
+ unreleasedFlag("notification_group_expansion_change")
// 200 - keyguard/lockscreen
// ** Flag retired **
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index 053c9b56ef96..60fd10492628 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -29,7 +29,10 @@ import android.os.Bundle
import android.os.IBinder
import android.os.ResultReceiver
import android.os.UserHandle
+import android.util.Log
+import android.view.View
import android.view.ViewGroup
+import android.view.accessibility.AccessibilityEvent
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
@@ -40,6 +43,9 @@ import com.android.internal.app.ChooserActivity
import com.android.internal.app.ResolverListController
import com.android.internal.app.chooser.NotSelectableTargetInfo
import com.android.internal.app.chooser.TargetInfo
+import com.android.internal.widget.RecyclerView
+import com.android.internal.widget.RecyclerViewAccessibilityDelegate
+import com.android.internal.widget.ResolverDrawerLayout
import com.android.systemui.R
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorComponent
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController
@@ -105,6 +111,10 @@ class MediaProjectionAppSelectorActivity(
super.onCreate(bundle)
controller.init()
+ // we override AppList's AccessibilityDelegate set in ResolverActivity.onCreate because in
+ // our case this delegate must extend RecyclerViewAccessibilityDelegate, otherwise
+ // RecyclerView scrolling is broken
+ setAppListAccessibilityDelegate()
}
override fun onStart() {
@@ -277,6 +287,8 @@ class MediaProjectionAppSelectorActivity(
recentsViewController.createView(parent)
companion object {
+ const val TAG = "MediaProjectionAppSelectorActivity"
+
/**
* When EXTRA_CAPTURE_REGION_RESULT_RECEIVER is passed as intent extra the activity will
* send the [CaptureRegion] to the result receiver instead of returning media projection
@@ -313,4 +325,42 @@ class MediaProjectionAppSelectorActivity(
putExtra(EXTRA_SELECTED_PROFILE, selectedProfile)
}
}
+
+ private fun setAppListAccessibilityDelegate() {
+ val rdl = requireViewById<ResolverDrawerLayout>(com.android.internal.R.id.contentPanel)
+ for (i in 0 until mMultiProfilePagerAdapter.count) {
+ val list =
+ mMultiProfilePagerAdapter
+ .getItem(i)
+ .rootView
+ .findViewById<View>(com.android.internal.R.id.resolver_list)
+ if (list == null || list !is RecyclerView) {
+ Log.wtf(TAG, "MediaProjection only supports RecyclerView")
+ } else {
+ list.accessibilityDelegate = RecyclerViewExpandingAccessibilityDelegate(rdl, list)
+ }
+ }
+ }
+
+ /**
+ * An a11y delegate propagating all a11y events to [AppListAccessibilityDelegate] so that it can
+ * expand drawer when needed. It needs to extend [RecyclerViewAccessibilityDelegate] because
+ * that superclass handles RecyclerView scrolling while using a11y services.
+ */
+ private class RecyclerViewExpandingAccessibilityDelegate(
+ rdl: ResolverDrawerLayout,
+ view: RecyclerView
+ ) : RecyclerViewAccessibilityDelegate(view) {
+
+ private val delegate = AppListAccessibilityDelegate(rdl)
+
+ override fun onRequestSendAccessibilityEvent(
+ host: ViewGroup,
+ child: View,
+ event: AccessibilityEvent
+ ): Boolean {
+ super.onRequestSendAccessibilityEvent(host, child, event)
+ return delegate.onRequestSendAccessibilityEvent(host, child, event)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 4be572f8c0f6..d403788f2c66 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -29,6 +29,7 @@ import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
+import android.app.StatusBarManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -72,6 +73,7 @@ public class MediaProjectionPermissionActivity extends Activity
private final FeatureFlags mFeatureFlags;
private final Lazy<ScreenCaptureDevicePolicyResolver> mScreenCaptureDevicePolicyResolver;
+ private final StatusBarManager mStatusBarManager;
private String mPackageName;
private int mUid;
@@ -87,9 +89,11 @@ public class MediaProjectionPermissionActivity extends Activity
@Inject
public MediaProjectionPermissionActivity(FeatureFlags featureFlags,
- Lazy<ScreenCaptureDevicePolicyResolver> screenCaptureDevicePolicyResolver) {
+ Lazy<ScreenCaptureDevicePolicyResolver> screenCaptureDevicePolicyResolver,
+ StatusBarManager statusBarManager) {
mFeatureFlags = featureFlags;
mScreenCaptureDevicePolicyResolver = screenCaptureDevicePolicyResolver;
+ mStatusBarManager = statusBarManager;
}
@Override
@@ -311,6 +315,8 @@ public class MediaProjectionPermissionActivity extends Activity
// WM Shell running inside.
mUserSelectingTask = true;
startActivityAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser()));
+ // close shade if it's open
+ mStatusBarManager.collapsePanels();
}
} catch (RemoteException e) {
Log.e(TAG, "Error granting projection permission", e);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 30218a6a3180..26912f82b3a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -226,7 +226,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
listenToMetadata(device);
} else {
stopListeningToStaleDeviceMetadata();
- batteryLevel = device.getBatteryLevel();
+ batteryLevel = device.getMinBatteryLevelWithMemberDevices();
}
if (batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index e41fb18e023f..53c9a0e95925 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -40,6 +40,7 @@ import android.view.IWindow;
import android.view.IWindowSession;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
@@ -401,9 +402,9 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
private void applyForceShowNavigationFlag(NotificationShadeWindowState state) {
if (state.panelExpanded || state.bouncerShowing
|| ENABLE_REMOTE_INPUT && state.remoteInputActive) {
- mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ mLpChanged.forciblyShownTypes |= WindowInsets.Type.navigationBars();
} else {
- mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ mLpChanged.forciblyShownTypes &= ~WindowInsets.Type.navigationBars();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 798f2d586bab..b4de914ce812 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -36,6 +36,7 @@ import com.android.keyguard.KeyguardMessageAreaController;
import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.R;
+import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.back.domain.interactor.BackActionInteractor;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;
@@ -288,7 +289,7 @@ public class NotificationShadeWindowViewController {
}
if (mExpandAnimationRunning) {
if (isDown && mClock.uptimeMillis() > mLaunchAnimationTimeout) {
- mShadeLogger.d("NSWVC: launch animation timed out");
+ Log.wtf(TAG, "NSWVC: launch animation timed out");
setExpandAnimationRunning(false);
} else {
return logDownDispatch(ev, "expand animation running", false);
@@ -545,6 +546,10 @@ public class NotificationShadeWindowViewController {
@VisibleForTesting
void setExpandAnimationRunning(boolean running) {
if (mExpandAnimationRunning != running) {
+ // TODO(b/288507023): Remove this log.
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "Setting mExpandAnimationRunning=" + running);
+ }
if (running) {
mLaunchAnimationTimeout = mClock.uptimeMillis() + 5000;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 91547a44c5f5..a08cd3bd869c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification
+import android.util.Log
import android.view.ViewGroup
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.animation.ActivityLaunchAnimator
@@ -30,6 +31,8 @@ import javax.inject.Inject
import kotlin.math.ceil
import kotlin.math.max
+private const val TAG = "NotificationLaunchAnimatorController"
+
/** A provider of [NotificationLaunchAnimatorController]. */
@CentralSurfacesComponent.CentralSurfacesScope
class NotificationLaunchAnimatorControllerProvider @Inject constructor(
@@ -89,28 +92,33 @@ class NotificationLaunchAnimatorController(
val clipStartLocation = notificationListContainer.topClippingStartLocation
val roundedTopClipping = (clipStartLocation - location[1]).coerceAtLeast(0)
val windowTop = location[1] + roundedTopClipping
- val topCornerRadius = if (roundedTopClipping > 0) {
- // Because the rounded Rect clipping is complex, we start the top rounding at
- // 0, which is pretty close to matching the real clipping.
- // We'd have to clipOut the overlaid drawable too with the outer rounded rect in case
- // if we'd like to have this perfect, but this is close enough.
- 0f
- } else {
- notification.topCornerRadius
- }
- val params = LaunchAnimationParameters(
- top = windowTop,
- bottom = location[1] + height,
- left = location[0],
- right = location[0] + notification.width,
- topCornerRadius = topCornerRadius,
- bottomCornerRadius = notification.bottomCornerRadius
- )
+ val topCornerRadius =
+ if (roundedTopClipping > 0) {
+ // Because the rounded Rect clipping is complex, we start the top rounding at
+ // 0, which is pretty close to matching the real clipping.
+ // We'd have to clipOut the overlaid drawable too with the outer rounded rect in
+ // case
+ // if we'd like to have this perfect, but this is close enough.
+ 0f
+ } else {
+ notification.topCornerRadius
+ }
+ val params =
+ LaunchAnimationParameters(
+ top = windowTop,
+ bottom = location[1] + height,
+ left = location[0],
+ right = location[0] + notification.width,
+ topCornerRadius = topCornerRadius,
+ bottomCornerRadius = notification.bottomCornerRadius
+ )
params.startTranslationZ = notification.translationZ
params.startNotificationTop = location[1]
- params.notificationParentTop = notificationListContainer
- .getViewParentForNotification(notificationEntry).locationOnScreen[1]
+ params.notificationParentTop =
+ notificationListContainer
+ .getViewParentForNotification(notificationEntry)
+ .locationOnScreen[1]
params.startRoundedTopClipping = roundedTopClipping
params.startClipTopAmount = notification.clipTopAmount
if (notification.isChildInGroup) {
@@ -135,6 +143,9 @@ class NotificationLaunchAnimatorController(
}
override fun onIntentStarted(willAnimate: Boolean) {
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "onIntentStarted(willAnimate=$willAnimate)")
+ }
notificationExpansionRepository.setIsExpandAnimationRunning(willAnimate)
notificationEntry.isExpandAnimationRunning = willAnimate
@@ -165,6 +176,10 @@ class NotificationLaunchAnimatorController(
}
override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "onLaunchAnimationCancelled()")
+ }
+
// TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started
// here?
notificationExpansionRepository.setIsExpandAnimationRunning(false)
@@ -177,11 +192,13 @@ class NotificationLaunchAnimatorController(
notification.isExpandAnimationRunning = true
notificationListContainer.setExpandingNotification(notification)
- jankMonitor.begin(notification,
- InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
+ jankMonitor.begin(notification, InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
}
override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "onLaunchAnimationEnd()")
+ }
jankMonitor.end(InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
notification.isExpandAnimationRunning = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt
index f605bdffbfd9..6f0a97adb311 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt
@@ -16,12 +16,16 @@
package com.android.systemui.statusbar.notification.data.repository
+import android.util.Log
+import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+private const val TAG = "NotificationExpansionRepository"
+
/** A repository tracking the status of notification expansion animations. */
@SysUISingleton
class NotificationExpansionRepository @Inject constructor() {
@@ -37,6 +41,9 @@ class NotificationExpansionRepository @Inject constructor() {
/** Sets whether the notification expansion animation is currently running. */
fun setIsExpandAnimationRunning(running: Boolean) {
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "setIsExpandAnimationRunning(running=$running)")
+ }
_isExpandAnimationRunning.value = running
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManager.java
index 51eb9f7220fc..c24e9dcea29d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManager.java
@@ -36,7 +36,7 @@ import javax.inject.Inject;
@SysUISingleton
public class NotifInflationErrorManager {
- Set<NotificationEntry> mErroredNotifs = new ArraySet<>();
+ Set<String> mErroredNotifs = new ArraySet<>();
List<NotifInflationErrorListener> mListeners = new ArrayList<>();
@Inject
@@ -48,7 +48,7 @@ public class NotifInflationErrorManager {
* @param e the exception encountered while inflating
*/
public void setInflationError(NotificationEntry entry, Exception e) {
- mErroredNotifs.add(entry);
+ mErroredNotifs.add(entry.getKey());
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onNotifInflationError(entry, e);
}
@@ -58,8 +58,8 @@ public class NotifInflationErrorManager {
* Notification inflated successfully and is no longer errored out.
*/
public void clearInflationError(NotificationEntry entry) {
- if (mErroredNotifs.contains(entry)) {
- mErroredNotifs.remove(entry);
+ if (mErroredNotifs.contains(entry.getKey())) {
+ mErroredNotifs.remove(entry.getKey());
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onNotifInflationErrorCleared(entry);
}
@@ -70,7 +70,7 @@ public class NotifInflationErrorManager {
* Whether or not the notification encountered an exception while inflating.
*/
public boolean hasInflationError(@NonNull NotificationEntry entry) {
- return mErroredNotifs.contains(entry);
+ return mErroredNotifs.contains(entry.getKey());
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 6db8df91edcc..05f837bc67cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1662,8 +1662,9 @@ public class NotificationStackScrollLayoutController {
@VisibleForTesting
void onKeyguardTransitionChanged(TransitionStep transitionStep) {
- boolean isTransitionToAod = transitionStep.getFrom().equals(KeyguardState.GONE)
- && transitionStep.getTo().equals(KeyguardState.AOD);
+ boolean isTransitionToAod = transitionStep.getTo().equals(KeyguardState.AOD)
+ && (transitionStep.getFrom().equals(KeyguardState.GONE)
+ || transitionStep.getFrom().equals(KeyguardState.OCCLUDED));
if (mIsInTransitionToAod != isTransitionToAod) {
mIsInTransitionToAod = isTransitionToAod;
updateShowEmptyShadeView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index ccb87bf44dc8..a243356c8690 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -624,7 +624,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private final ActivityLaunchAnimator mActivityLaunchAnimator;
private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
- private final NotificationPresenter mPresenter;
+ private final Lazy<NotificationPresenter> mPresenterLazy;
private NotificationActivityStarter mNotificationActivityStarter;
private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
private final Optional<Bubbles> mBubblesOptional;
@@ -725,7 +725,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
Lazy<NotificationShadeWindowViewController> notificationShadeWindowViewControllerLazy,
NotificationShelfController notificationShelfController,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
- NotificationPresenter notificationPresenter,
+ // Lazy due to b/298099682.
+ Lazy<NotificationPresenter> notificationPresenterLazy,
NotificationExpansionRepository notificationExpansionRepository,
DozeParameters dozeParameters,
ScrimController scrimController,
@@ -833,7 +834,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mStackScrollerController = notificationStackScrollLayoutController;
mStackScroller = mStackScrollerController.getView();
mNotifListContainer = mStackScrollerController.getNotificationListContainer();
- mPresenter = notificationPresenter;
+ mPresenterLazy = notificationPresenterLazy;
mNotificationExpansionRepository = notificationExpansionRepository;
mDozeServiceHost = dozeServiceHost;
mPowerManager = powerManager;
@@ -1556,9 +1557,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
- mShadeController.setNotificationPresenter(mPresenter);
+ mShadeController.setNotificationPresenter(mPresenterLazy.get());
mNotificationsController.initialize(
- mPresenter,
+ mPresenterLazy.get(),
mNotifListContainer,
mStackScrollerController.getNotifStackController(),
mNotificationActivityStarter);
@@ -1736,12 +1737,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
@Override
public boolean isDeviceInVrMode() {
- return mPresenter.isDeviceInVrMode();
+ return mPresenterLazy.get().isDeviceInVrMode();
}
@Override
public NotificationPresenter getPresenter() {
- return mPresenter;
+ return mPresenterLazy.get();
}
@VisibleForTesting
@@ -2148,7 +2149,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
String action = intent.getAction();
if (ACTION_FAKE_ARTWORK.equals(action)) {
if (DEBUG_MEDIA_FAKE_ARTWORK) {
- mPresenter.updateMediaMetaData(true, true);
+ mPresenterLazy.get().updateMediaMetaData(true, true);
}
}
}
@@ -2234,10 +2235,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
*/
boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
boolean clearNotificationEffects =
- !mPresenter.isPresenterFullyCollapsed() && (mState == StatusBarState.SHADE
+ !mPresenterLazy.get().isPresenterFullyCollapsed() && (mState == StatusBarState.SHADE
|| mState == StatusBarState.SHADE_LOCKED);
int notificationLoad = mNotificationsController.getActiveNotificationsCount();
- if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
+ if (pinnedHeadsUp && mPresenterLazy.get().isPresenterFullyCollapsed()) {
notificationLoad = 1;
}
final int finalNotificationLoad = notificationLoad;
@@ -2405,7 +2406,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
releaseGestureWakeLock();
runLaunchTransitionEndRunnable();
mKeyguardStateController.setLaunchTransitionFadingAway(false);
- mPresenter.updateMediaMetaData(true /* metaDataChanged */, true);
+ mPresenterLazy.get().updateMediaMetaData(true /* metaDataChanged */, true);
}
/**
@@ -2429,7 +2430,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
beforeFading.run();
}
updateScrimController();
- mPresenter.updateMediaMetaData(false, true);
+ mPresenterLazy.get().updateMediaMetaData(false, true);
mShadeSurface.resetAlpha();
mShadeSurface.fadeOut(
FADE_KEYGUARD_START_DELAY, FADE_KEYGUARD_DURATION,
@@ -3564,7 +3565,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
updateDozingState();
checkBarModes();
updateScrimController();
- mPresenter.updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
+ mPresenterLazy.get()
+ .updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 62a8cfde80da..b0f8276e460d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -763,7 +763,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
* Sets the amount of vertical over scroll that should be performed on the notifications scrim.
*/
public void setNotificationsOverScrollAmount(int overScrollAmount) {
- mNotificationsScrim.setTranslationY(overScrollAmount);
+ if (mNotificationsScrim != null) mNotificationsScrim.setTranslationY(overScrollAmount);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
index 24987abd7a85..f4cc0ed30781 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -21,7 +21,6 @@ import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowInsets.Type.tappableElement;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
@@ -44,6 +43,7 @@ import android.view.InsetsFrameProvider;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.WindowManager;
import com.android.internal.policy.SystemBarUtils;
@@ -361,9 +361,9 @@ public class StatusBarWindowController {
|| state.mIsLaunchAnimationRunning
// Don't force-show the status bar if the user has already dismissed it.
|| state.mOngoingProcessRequiresStatusBarVisible) {
- mLpChanged.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
+ mLpChanged.forciblyShownTypes |= WindowInsets.Type.statusBars();
} else {
- mLpChanged.privateFlags &= ~PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
+ mLpChanged.forciblyShownTypes &= ~WindowInsets.Type.statusBars();
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index e96ad876db3a..7ac80922e6a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -712,6 +712,245 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
}
@Test
+ public void windowWidthIsNotMax_performA11yActionIncreaseWidth_windowWidthIncreased() {
+ final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ final int startingWidth = (int) (windowBounds.width() * 0.8);
+ final int startingHeight = (int) (windowBounds.height() * 0.8);
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mirrorView.performAccessibilityAction(
+ R.id.accessibility_action_increase_window_width, null);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+ R.dimen.magnification_mirror_surface_margin);
+ // Window width includes the magnifier frame and the margin. Increasing the window size
+ // will be increasing the amount of the frame size only.
+ int newWindowWidth =
+ (int) ((startingWidth - 2 * mirrorSurfaceMargin) * (1 + changeWindowSizeAmount))
+ + 2 * mirrorSurfaceMargin;
+ assertEquals(newWindowWidth, actualWindowWidth.get());
+ assertEquals(startingHeight, actualWindowHeight.get());
+ }
+
+ @Test
+ public void windowHeightIsNotMax_performA11yActionIncreaseHeight_windowHeightIncreased() {
+ final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ final int startingWidth = (int) (windowBounds.width() * 0.8);
+ final int startingHeight = (int) (windowBounds.height() * 0.8);
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mirrorView.performAccessibilityAction(
+ R.id.accessibility_action_increase_window_height, null);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+ R.dimen.magnification_mirror_surface_margin);
+ // Window height includes the magnifier frame and the margin. Increasing the window size
+ // will be increasing the amount of the frame size only.
+ int newWindowHeight =
+ (int) ((startingHeight - 2 * mirrorSurfaceMargin) * (1 + changeWindowSizeAmount))
+ + 2 * mirrorSurfaceMargin;
+ assertEquals(startingWidth, actualWindowWidth.get());
+ assertEquals(newWindowHeight, actualWindowHeight.get());
+ }
+
+ @Test
+ public void windowWidthIsMax_noIncreaseWindowWidthA11yAction() {
+ final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ final int startingWidth = windowBounds.width();
+ final int startingHeight = windowBounds.height();
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AccessibilityNodeInfo accessibilityNodeInfo =
+ mirrorView.createAccessibilityNodeInfo();
+ assertFalse(accessibilityNodeInfo.getActionList().contains(
+ new AccessibilityAction(R.id.accessibility_action_increase_window_width, null)));
+ }
+
+ @Test
+ public void windowHeightIsMax_noIncreaseWindowHeightA11yAction() {
+ final Rect windowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ final int startingWidth = windowBounds.width();
+ final int startingHeight = windowBounds.height();
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AccessibilityNodeInfo accessibilityNodeInfo =
+ mirrorView.createAccessibilityNodeInfo();
+ assertFalse(accessibilityNodeInfo.getActionList().contains(
+ new AccessibilityAction(R.id.accessibility_action_increase_window_height, null)));
+ }
+
+ @Test
+ public void windowWidthIsNotMin_performA11yActionDecreaseWidth_windowWidthDecreased() {
+ int mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int startingSize = (int) (mMinWindowSize * 1.1);
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mirrorView.performAccessibilityAction(
+ R.id.accessibility_action_decrease_window_width, null);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+ R.dimen.magnification_mirror_surface_margin);
+ // Window width includes the magnifier frame and the margin. Decreasing the window size
+ // will be decreasing the amount of the frame size only.
+ int newWindowWidth =
+ (int) ((startingSize - 2 * mirrorSurfaceMargin) * (1 - changeWindowSizeAmount))
+ + 2 * mirrorSurfaceMargin;
+ assertEquals(newWindowWidth, actualWindowWidth.get());
+ assertEquals(startingSize, actualWindowHeight.get());
+ }
+
+ @Test
+ public void windowHeightIsNotMin_performA11yActionDecreaseHeight_windowHeightDecreased() {
+ int mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int startingSize = (int) (mMinWindowSize * 1.1);
+ final float changeWindowSizeAmount = mContext.getResources().getFraction(
+ R.fraction.magnification_resize_window_size_amount,
+ /* base= */ 1,
+ /* pbase= */ 1);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ mirrorView.performAccessibilityAction(
+ R.id.accessibility_action_decrease_window_height, null);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ final int mirrorSurfaceMargin = mResources.getDimensionPixelSize(
+ R.dimen.magnification_mirror_surface_margin);
+ // Window height includes the magnifier frame and the margin. Decreasing the window size
+ // will be decreasing the amount of the frame size only.
+ int newWindowHeight =
+ (int) ((startingSize - 2 * mirrorSurfaceMargin) * (1 - changeWindowSizeAmount))
+ + 2 * mirrorSurfaceMargin;
+ assertEquals(startingSize, actualWindowWidth.get());
+ assertEquals(newWindowHeight, actualWindowHeight.get());
+ }
+
+ @Test
+ public void windowWidthIsMin_noDecreaseWindowWidthA11yAction() {
+ int mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int startingSize = mMinWindowSize;
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AccessibilityNodeInfo accessibilityNodeInfo =
+ mirrorView.createAccessibilityNodeInfo();
+ assertFalse(accessibilityNodeInfo.getActionList().contains(
+ new AccessibilityAction(R.id.accessibility_action_decrease_window_width, null)));
+ }
+
+ @Test
+ public void windowHeightIsMin_noDecreaseWindowHeightA11yAcyion() {
+ int mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int startingSize = mMinWindowSize;
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ mWindowMagnificationController.setWindowSize(startingSize, startingSize);
+ mWindowMagnificationController.setEditMagnifierSizeMode(true);
+ });
+
+ final View mirrorView = mWindowManager.getAttachedView();
+ final AccessibilityNodeInfo accessibilityNodeInfo =
+ mirrorView.createAccessibilityNodeInfo();
+ assertFalse(accessibilityNodeInfo.getActionList().contains(
+ new AccessibilityAction(R.id.accessibility_action_decrease_window_height, null)));
+ }
+
+ @Test
public void enableWindowMagnification_hasA11yWindowTitle() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
@@ -1166,4 +1405,5 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
when(mContext.getDisplay()).thenReturn(display);
return newRotation;
}
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
index 239e317b92f5..ed9ae5e3dc01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
@@ -29,6 +29,7 @@ import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.coroutines.collectLastValue
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -44,6 +45,7 @@ import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class FingerprintRepositoryImplTest : SysuiTestCase() {
@@ -73,10 +75,15 @@ class FingerprintRepositoryImplTest : SysuiTestCase() {
@Test
fun initializeProperties() =
testScope.runTest {
- val isInitialized = collectLastValue(repository.isInitialized)
+ val sensorId by collectLastValue(repository.sensorId)
+ val strength by collectLastValue(repository.strength)
+ val sensorType by collectLastValue(repository.sensorType)
+ val sensorLocations by collectLastValue(repository.sensorLocations)
- assertDefaultProperties()
- assertThat(isInitialized()).isFalse()
+ // Assert default properties.
+ assertThat(sensorId).isEqualTo(-1)
+ assertThat(strength).isEqualTo(SensorStrength.CONVENIENCE)
+ assertThat(sensorType).isEqualTo(FingerprintSensorType.UNKNOWN)
val fingerprintProps =
listOf(
@@ -115,31 +122,24 @@ class FingerprintRepositoryImplTest : SysuiTestCase() {
fingerprintAuthenticatorsCaptor.value.onAllAuthenticatorsRegistered(fingerprintProps)
- assertThat(repository.sensorId.value).isEqualTo(1)
- assertThat(repository.strength.value).isEqualTo(SensorStrength.STRONG)
- assertThat(repository.sensorType.value).isEqualTo(FingerprintSensorType.REAR)
+ assertThat(sensorId).isEqualTo(1)
+ assertThat(strength).isEqualTo(SensorStrength.STRONG)
+ assertThat(sensorType).isEqualTo(FingerprintSensorType.REAR)
- assertThat(repository.sensorLocations.value.size).isEqualTo(2)
- assertThat(repository.sensorLocations.value).containsKey("display_id_1")
- with(repository.sensorLocations.value["display_id_1"]!!) {
+ assertThat(sensorLocations?.size).isEqualTo(2)
+ assertThat(sensorLocations).containsKey("display_id_1")
+ with(sensorLocations?.get("display_id_1")!!) {
assertThat(displayId).isEqualTo("display_id_1")
assertThat(sensorLocationX).isEqualTo(100)
assertThat(sensorLocationY).isEqualTo(300)
assertThat(sensorRadius).isEqualTo(20)
}
- assertThat(repository.sensorLocations.value).containsKey("")
- with(repository.sensorLocations.value[""]!!) {
+ assertThat(sensorLocations).containsKey("")
+ with(sensorLocations?.get("")!!) {
assertThat(displayId).isEqualTo("")
assertThat(sensorLocationX).isEqualTo(540)
assertThat(sensorLocationY).isEqualTo(1636)
assertThat(sensorRadius).isEqualTo(130)
}
- assertThat(isInitialized()).isTrue()
}
-
- private fun assertDefaultProperties() {
- assertThat(repository.sensorId.value).isEqualTo(-1)
- assertThat(repository.strength.value).isEqualTo(SensorStrength.CONVENIENCE)
- assertThat(repository.sensorType.value).isEqualTo(FingerprintSensorType.UNKNOWN)
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt
index fd96cf45504b..712eef13421b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt
@@ -22,6 +22,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.coroutines.collectLastValue
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -51,7 +52,7 @@ class SideFpsOverlayInteractorTest : SysuiTestCase() {
}
@Test
- fun testGetOverlayOffsets() =
+ fun testOverlayOffsetUpdates() =
testScope.runTest {
fingerprintRepository.setProperties(
sensorId = 1,
@@ -76,16 +77,32 @@ class SideFpsOverlayInteractorTest : SysuiTestCase() {
)
)
- var offsets = interactor.getOverlayOffsets("display_id_1")
- assertThat(offsets.displayId).isEqualTo("display_id_1")
- assertThat(offsets.sensorLocationX).isEqualTo(100)
- assertThat(offsets.sensorLocationY).isEqualTo(300)
- assertThat(offsets.sensorRadius).isEqualTo(20)
+ val displayId by collectLastValue(interactor.displayId)
+ val offsets by collectLastValue(interactor.overlayOffsets)
- offsets = interactor.getOverlayOffsets("invalid_display_id")
- assertThat(offsets.displayId).isEqualTo("")
- assertThat(offsets.sensorLocationX).isEqualTo(540)
- assertThat(offsets.sensorLocationY).isEqualTo(1636)
- assertThat(offsets.sensorRadius).isEqualTo(130)
+ // Assert offsets of empty displayId.
+ assertThat(displayId).isEqualTo("")
+ assertThat(offsets?.displayId).isEqualTo("")
+ assertThat(offsets?.sensorLocationX).isEqualTo(540)
+ assertThat(offsets?.sensorLocationY).isEqualTo(1636)
+ assertThat(offsets?.sensorRadius).isEqualTo(130)
+
+ // Offsets should be updated correctly.
+ interactor.onDisplayChanged("display_id_1")
+ assertThat(displayId).isEqualTo("display_id_1")
+ assertThat(offsets?.displayId).isEqualTo("display_id_1")
+ assertThat(offsets?.sensorLocationX).isEqualTo(100)
+ assertThat(offsets?.sensorLocationY).isEqualTo(300)
+ assertThat(offsets?.sensorRadius).isEqualTo(20)
+
+ // Should return default offset when the displayId is invalid.
+ interactor.onDisplayChanged("invalid_display_id")
+ assertThat(displayId).isEqualTo("invalid_display_id")
+ assertThat(offsets?.displayId).isEqualTo(SensorLocationInternal.DEFAULT.displayId)
+ assertThat(offsets?.sensorLocationX)
+ .isEqualTo(SensorLocationInternal.DEFAULT.sensorLocationX)
+ assertThat(offsets?.sensorLocationY)
+ .isEqualTo(SensorLocationInternal.DEFAULT.sensorLocationY)
+ assertThat(offsets?.sensorRadius).isEqualTo(SensorLocationInternal.DEFAULT.sensorRadius)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
index 5e7f68ccf3d7..e5c55d8b6c56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
@@ -168,7 +168,7 @@ class BluetoothTileTest : SysuiTestCase() {
val btDevice = mock<BluetoothDevice>()
whenever(cachedDevice2.device).thenReturn(btDevice)
whenever(btDevice.getMetadata(BluetoothDevice.METADATA_MAIN_BATTERY)).thenReturn(null)
- whenever(cachedDevice2.batteryLevel).thenReturn(25)
+ whenever(cachedDevice2.minBatteryLevelWithMemberDevices).thenReturn(25)
addConnectedDevice(cachedDevice2)
tile.handleUpdateState(state, /* arg= */ null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
new file mode 100644
index 000000000000..e38adeb0fcd9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
@@ -0,0 +1,97 @@
+/*
+ * 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.systemui.statusbar.notification.row
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager.NotifInflationErrorListener
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class NotifInflationErrorManagerTest : SysuiTestCase() {
+ private lateinit var manager: NotifInflationErrorManager
+
+ private val listener1 = mock(NotifInflationErrorListener::class.java)
+ private val listener2 = mock(NotifInflationErrorListener::class.java)
+
+ private val foo: NotificationEntry = NotificationEntryBuilder().setPkg("foo").build()
+ private val bar: NotificationEntry = NotificationEntryBuilder().setPkg("bar").build()
+ private val baz: NotificationEntry = NotificationEntryBuilder().setPkg("baz").build()
+
+ private val fooException = Exception("foo")
+ private val barException = Exception("bar")
+
+ @Before
+ fun setUp() {
+ // Reset manager instance before each test.
+ manager = NotifInflationErrorManager()
+ }
+
+ @Test
+ fun testTracksInflationErrors() {
+ manager.setInflationError(foo, fooException)
+ manager.setInflationError(bar, barException)
+
+ assertThat(manager.hasInflationError(foo)).isTrue()
+ assertThat(manager.hasInflationError(bar)).isTrue()
+ assertThat(manager.hasInflationError(baz)).isFalse()
+
+ manager.clearInflationError(bar)
+
+ assertThat(manager.hasInflationError(bar)).isFalse()
+ }
+
+ @Test
+ fun testNotifiesListeners() {
+ manager.addInflationErrorListener(listener1)
+ manager.setInflationError(foo, fooException)
+
+ verify(listener1).onNotifInflationError(foo, fooException)
+
+ manager.addInflationErrorListener(listener2)
+ manager.setInflationError(bar, barException)
+
+ verify(listener1).onNotifInflationError(bar, barException)
+ verify(listener2).onNotifInflationError(bar, barException)
+
+ manager.clearInflationError(foo)
+
+ verify(listener1).onNotifInflationErrorCleared(foo)
+ verify(listener2).onNotifInflationErrorCleared(foo)
+ }
+
+ @Test
+ fun testClearUnknownEntry() {
+ manager.addInflationErrorListener(listener1)
+ manager.clearInflationError(foo)
+
+ verify(listener1, never()).onNotifInflationErrorCleared(any())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 6f431be29d73..79cf932a1880 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -628,6 +628,16 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
verify(mNotificationStackScrollLayout).updateEmptyShadeView(eq(false), anyBoolean());
}
+ @Test
+ public void updateEmptyShadeView_onKeyguardOccludedTransitionToAod_hidesView() {
+ initController(/* viewIsAttached= */ true);
+ mController.onKeyguardTransitionChanged(
+ new TransitionStep(
+ /* from= */ KeyguardState.OCCLUDED,
+ /* to= */ KeyguardState.AOD));
+ verify(mNotificationStackScrollLayout).updateEmptyShadeView(eq(false), anyBoolean());
+ }
+
private LogMaker logMatcher(int category, int type) {
return argThat(new LogMatcher(category, type));
}
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 39b294879450..de00747df4e2 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
@@ -516,7 +516,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mNotificationShadeWindowViewControllerLazy,
mNotificationShelfController,
mStackScrollerController,
- mNotificationPresenter,
+ () -> mNotificationPresenter,
new NotificationExpansionRepository(),
mDozeParameters,
mScrimController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index d01e0a6f933f..a82088285e84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -84,7 +84,7 @@ import java.util.function.Predicate;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class VolumeDialogImplTest extends SysuiTestCase {
VolumeDialogImpl mDialog;
View mActiveRinger;
@@ -141,6 +141,7 @@ public class VolumeDialogImplTest extends SysuiTestCase {
getContext().addMockSystemService(KeyguardManager.class, mKeyguard);
mTestableLooper = TestableLooper.get(this);
+ allowTestableLooperAsMainThread();
when(mPostureController.getDevicePosture())
.thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
index 2362a5241244..0c5e43809fab 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
@@ -20,16 +20,12 @@ import android.hardware.biometrics.SensorLocationInternal
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
class FakeFingerprintPropertyRepository : FingerprintPropertyRepository {
- private val _isInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false)
- override val isInitialized = _isInitialized.asStateFlow()
-
private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
- override val sensorId: StateFlow<Int> = _sensorId.asStateFlow()
+ override val sensorId = _sensorId.asStateFlow()
private val _strength: MutableStateFlow<SensorStrength> =
MutableStateFlow(SensorStrength.CONVENIENCE)
@@ -37,12 +33,11 @@ class FakeFingerprintPropertyRepository : FingerprintPropertyRepository {
private val _sensorType: MutableStateFlow<FingerprintSensorType> =
MutableStateFlow(FingerprintSensorType.UNKNOWN)
- override val sensorType: StateFlow<FingerprintSensorType> = _sensorType.asStateFlow()
+ override val sensorType = _sensorType.asStateFlow()
private val _sensorLocations: MutableStateFlow<Map<String, SensorLocationInternal>> =
MutableStateFlow(mapOf("" to SensorLocationInternal.DEFAULT))
- override val sensorLocations: StateFlow<Map<String, SensorLocationInternal>> =
- _sensorLocations.asStateFlow()
+ override val sensorLocations = _sensorLocations.asStateFlow()
fun setProperties(
sensorId: Int,
@@ -54,6 +49,5 @@ class FakeFingerprintPropertyRepository : FingerprintPropertyRepository {
_strength.value = strength
_sensorType.value = sensorType
_sensorLocations.value = sensorLocations
- _isInitialized.value = true
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 459c6ff3504a..9a4ff54be795 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2513,9 +2513,7 @@ public class OomAdjuster {
}
}
- if (schedGroup < SCHED_GROUP_TOP_APP
- && cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP)
- && clientIsSystem) {
+ if (cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP) && clientIsSystem) {
schedGroup = SCHED_GROUP_TOP_APP;
scheduleLikeTopApp = true;
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index bf3f63c1ed30..d2737e81c55f 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -539,6 +539,62 @@ public class AudioDeviceBroker {
}
}
}
+
+ // check playback or record activity after 6 seconds for UIDs
+ private static final int CHECK_CLIENT_STATE_DELAY_MS = 6000;
+
+ /*package */
+ void postCheckCommunicationRouteClientState(int uid, boolean wasActive, int delay) {
+ CommunicationRouteClient client = getCommunicationRouteClientForUid(uid);
+ if (client != null) {
+ sendMsgForCheckClientState(MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE,
+ SENDMSG_REPLACE,
+ uid,
+ wasActive ? 1 : 0,
+ client,
+ delay);
+ }
+ }
+
+ @GuardedBy("mDeviceStateLock")
+ void onCheckCommunicationRouteClientState(int uid, boolean wasActive) {
+ CommunicationRouteClient client = getCommunicationRouteClientForUid(uid);
+ if (client == null) {
+ return;
+ }
+ updateCommunicationRouteClientState(client, wasActive);
+ }
+
+ @GuardedBy("mDeviceStateLock")
+ /*package*/ void updateCommunicationRouteClientState(
+ CommunicationRouteClient client, boolean wasActive) {
+ boolean wasBtScoRequested = isBluetoothScoRequested();
+ client.setPlaybackActive(mAudioService.isPlaybackActiveForUid(client.getUid()));
+ client.setRecordingActive(mAudioService.isRecordingActiveForUid(client.getUid()));
+ if (wasActive != client.isActive()) {
+ postUpdateCommunicationRouteClient(
+ wasBtScoRequested, "updateCommunicationRouteClientState");
+ }
+ }
+
+ @GuardedBy("mDeviceStateLock")
+ /*package*/ void setForceCommunicationClientStateAndDelayedCheck(
+ CommunicationRouteClient client,
+ boolean forcePlaybackActive,
+ boolean forceRecordingActive) {
+ if (client == null) {
+ return;
+ }
+ if (forcePlaybackActive) {
+ client.setPlaybackActive(true);
+ }
+ if (forceRecordingActive) {
+ client.setRecordingActive(true);
+ }
+ postCheckCommunicationRouteClientState(
+ client.getUid(), client.isActive(), CHECK_CLIENT_STATE_DELAY_MS);
+ }
+
/* package */ static List<AudioDeviceInfo> getAvailableCommunicationDevices() {
ArrayList<AudioDeviceInfo> commDevices = new ArrayList<>();
AudioDeviceInfo[] allDevices =
@@ -1901,6 +1957,12 @@ public class AudioDeviceBroker {
case MSG_PERSIST_AUDIO_DEVICE_SETTINGS:
onPersistAudioDeviceSettings();
break;
+
+ case MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE: {
+ synchronized (mDeviceStateLock) {
+ onCheckCommunicationRouteClientState(msg.arg1, msg.arg2 == 1);
+ }
+ } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -1982,6 +2044,8 @@ public class AudioDeviceBroker {
private static final int MSG_L_RECEIVED_BT_EVENT = 55;
+ private static final int MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE = 56;
+
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
@@ -2095,6 +2159,23 @@ public class AudioDeviceBroker {
}
}
+ private void removeMsgForCheckClientState(int uid) {
+ CommunicationRouteClient crc = getCommunicationRouteClientForUid(uid);
+ if (crc != null) {
+ mBrokerHandler.removeEqualMessages(MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE, crc);
+ }
+ }
+
+ private void sendMsgForCheckClientState(int msg, int existingMsgPolicy,
+ int arg1, int arg2, Object obj, int delay) {
+ if ((existingMsgPolicy == SENDMSG_REPLACE) && (obj != null)) {
+ mBrokerHandler.removeEqualMessages(msg, obj);
+ }
+
+ long time = SystemClock.uptimeMillis() + delay;
+ mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), time);
+ }
+
/** List of messages for which music is muted while processing is pending */
private static final Set<Integer> MESSAGES_MUTE_MUSIC;
static {
@@ -2367,6 +2448,7 @@ public class AudioDeviceBroker {
if (unregister) {
cl.unregisterDeathRecipient();
}
+ removeMsgForCheckClientState(cl.getUid());
mCommunicationRouteClients.remove(cl);
return cl;
}
@@ -2383,6 +2465,13 @@ public class AudioDeviceBroker {
new CommunicationRouteClient(cb, uid, device, isPrivileged);
if (client.registerDeathRecipient()) {
mCommunicationRouteClients.add(0, client);
+ if (!client.isActive()) {
+ // initialize the inactive client's state as active and check it after 6 seconds
+ setForceCommunicationClientStateAndDelayedCheck(
+ client,
+ !mAudioService.isPlaybackActiveForUid(client.getUid()),
+ !mAudioService.isRecordingActiveForUid(client.getUid()));
+ }
return client;
}
return null;
@@ -2439,16 +2528,16 @@ public class AudioDeviceBroker {
List<AudioRecordingConfiguration> recordConfigs) {
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
- final boolean wasBtScoRequested = isBluetoothScoRequested();
- boolean updateCommunicationRoute = false;
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
boolean wasActive = crc.isActive();
+ boolean updateClientState = false;
if (playbackConfigs != null) {
crc.setPlaybackActive(false);
for (AudioPlaybackConfiguration config : playbackConfigs) {
if (config.getClientUid() == crc.getUid()
&& config.isActive()) {
crc.setPlaybackActive(true);
+ updateClientState = true;
break;
}
}
@@ -2459,18 +2548,23 @@ public class AudioDeviceBroker {
if (config.getClientUid() == crc.getUid()
&& !config.isClientSilenced()) {
crc.setRecordingActive(true);
+ updateClientState = true;
break;
}
}
}
- if (wasActive != crc.isActive()) {
- updateCommunicationRoute = true;
+ if (updateClientState) {
+ removeMsgForCheckClientState(crc.getUid());
+ updateCommunicationRouteClientState(crc, wasActive);
+ } else {
+ if (wasActive) {
+ setForceCommunicationClientStateAndDelayedCheck(
+ crc,
+ playbackConfigs != null /* forcePlaybackActive */,
+ recordConfigs != null /* forceRecordingActive */);
+ }
}
}
- if (updateCommunicationRoute) {
- postUpdateCommunicationRouteClient(
- wasBtScoRequested, "updateCommunicationRouteClientsActivity");
- }
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 58f48f3b8007..a6be434a9abc 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -164,6 +164,7 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceDebugInfo;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
@@ -12945,12 +12946,25 @@ public class AudioService extends IAudioService.Stub
private static final String AUDIO_HAL_SERVICE_PREFIX = "android.hardware.audio";
- private Set<Integer> getAudioHalPids() {
+ private void getAudioAidlHalPids(HashSet<Integer> pids) {
+ try {
+ ServiceDebugInfo[] infos = ServiceManager.getServiceDebugInfo();
+ if (infos == null) return;
+ for (ServiceDebugInfo info : infos) {
+ if (info.debugPid > 0 && info.name.startsWith(AUDIO_HAL_SERVICE_PREFIX)) {
+ pids.add(info.debugPid);
+ }
+ }
+ } catch (RuntimeException e) {
+ // ignored, pid hashset does not change
+ }
+ }
+
+ private void getAudioHalHidlPids(HashSet<Integer> pids) {
try {
IServiceManager serviceManager = IServiceManager.getService();
ArrayList<IServiceManager.InstanceDebugInfo> dump =
serviceManager.debugDump();
- HashSet<Integer> pids = new HashSet<>();
for (IServiceManager.InstanceDebugInfo info : dump) {
if (info.pid != IServiceManager.PidConstant.NO_PID
&& info.interfaceName != null
@@ -12958,12 +12972,18 @@ public class AudioService extends IAudioService.Stub
pids.add(info.pid);
}
}
- return pids;
} catch (RemoteException | RuntimeException e) {
- return new HashSet<Integer>();
+ // ignored, pid hashset does not change
}
}
+ private Set<Integer> getAudioHalPids() {
+ HashSet<Integer> pids = new HashSet<>();
+ getAudioAidlHalPids(pids);
+ getAudioHalHidlPids(pids);
+ return pids;
+ }
+
private void updateAudioHalPids() {
Set<Integer> pidsSet = getAudioHalPids();
if (pidsSet.isEmpty()) {
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 5ebc1c055b50..95b6c2cef963 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -334,9 +334,8 @@ public class SoundDoseHelper {
SAFE_MEDIA_VOLUME_UNINITIALIZED);
mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
SAFE_MEDIA_VOLUME_UNINITIALIZED);
- // TODO(b/278265907): enable A2DP when we can distinguish A2DP headsets
- // mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- // SAFE_MEDIA_VOLUME_UNINITIALIZED);
+ mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ SAFE_MEDIA_VOLUME_UNINITIALIZED);
}
float getOutputRs2UpperBound() {
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
index fdf607d04ec7..64691e0b062b 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
@@ -53,6 +53,9 @@ public class AuthenticationStatsCollector {
static final int MAXIMUM_ENROLLMENT_NOTIFICATIONS = 1;
@NonNull private final Context mContext;
+ @NonNull private final PackageManager mPackageManager;
+ @NonNull private final FaceManager mFaceManager;
+ @NonNull private final FingerprintManager mFingerprintManager;
private final float mThreshold;
private final int mModality;
@@ -86,6 +89,10 @@ public class AuthenticationStatsCollector {
mModality = modality;
mBiometricNotification = biometricNotification;
+ mPackageManager = context.getPackageManager();
+ mFaceManager = mContext.getSystemService(FaceManager.class);
+ mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
context.registerReceiver(mBroadcastReceiver, intentFilter);
@@ -108,6 +115,13 @@ public class AuthenticationStatsCollector {
/** Update total authentication and rejected attempts. */
public void authenticate(int userId, boolean authenticated) {
+
+ // Don't collect data for single-modality devices or user has both biometrics enrolled.
+ if (isSingleModalityDevice()
+ || (hasEnrolledFace(userId) && hasEnrolledFingerprint(userId))) {
+ return;
+ }
+
// SharedPreference is not ready when starting system server, initialize
// mUserAuthenticationStatsMap in authentication to ensure SharedPreference
// is ready for application use.
@@ -150,25 +164,9 @@ public class AuthenticationStatsCollector {
authenticationStats.resetData();
- final PackageManager packageManager = mContext.getPackageManager();
-
- // Don't send notification to single-modality devices.
- if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
- || !packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
- return;
- }
-
- final FaceManager faceManager = mContext.getSystemService(FaceManager.class);
- final boolean hasEnrolledFace = faceManager.hasEnrolledTemplates(userId);
+ final boolean hasEnrolledFace = hasEnrolledFace(userId);
+ final boolean hasEnrolledFingerprint = hasEnrolledFingerprint(userId);
- final FingerprintManager fingerprintManager = mContext
- .getSystemService(FingerprintManager.class);
- final boolean hasEnrolledFingerprint = fingerprintManager.hasEnrolledTemplates(userId);
-
- // Don't send notification when both face and fingerprint are enrolled.
- if (hasEnrolledFace && hasEnrolledFingerprint) {
- return;
- }
if (hasEnrolledFace && !hasEnrolledFingerprint) {
mBiometricNotification.sendFpEnrollNotification(mContext);
authenticationStats.updateNotificationCounter();
@@ -199,6 +197,19 @@ public class AuthenticationStatsCollector {
}
}
+ private boolean isSingleModalityDevice() {
+ return !mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
+ || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE);
+ }
+
+ private boolean hasEnrolledFace(int userId) {
+ return mFaceManager.hasEnrolledTemplates(userId);
+ }
+
+ private boolean hasEnrolledFingerprint(int userId) {
+ return mFingerprintManager.hasEnrolledTemplates(userId);
+ }
+
/**
* Only being used in tests. Callers should not make any changes to the returned
* authentication stats.
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
index f1c74f0b9fb2..2aec9aefa8d1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
@@ -176,6 +176,7 @@ public class BiometricNotificationUtils {
.setSmallIcon(R.drawable.ic_lock)
.setContentTitle(title)
.setContentText(content)
+ .setStyle(new Notification.BigTextStyle().bigText(content))
.setSubText(name)
.setOnlyAlertOnce(true)
.setLocalOnly(true)
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 51a938558e57..4502e5d0c4b6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -128,7 +128,11 @@ class FingerprintDetectClient extends AcquisitionClient<AidlSession> implements
vibrateSuccess();
try {
- getListener().onDetected(getSensorId(), getTargetUserId(), mIsStrongBiometric);
+ if (getListener() != null) {
+ getListener().onDetected(getSensorId(), getTargetUserId(), mIsStrongBiometric);
+ } else {
+ Slog.e(TAG, "Listener is null!");
+ }
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when sending onDetected", e);
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 46cd496bdcd3..46d56ba5fea8 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -401,6 +401,12 @@ final class ColorFade {
}
}
+ void stop() {
+ if (mEglContext != null && mEglDisplay != null) {
+ EGL14.eglDestroyContext(mEglDisplay, mEglContext);
+ }
+ }
+
/**
* Draws an animation frame showing the color fade activated at the
* specified level.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6546f6e533c0..53921d4d83b5 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -143,6 +143,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.SettingsWrapper;
import com.android.server.AnimationThread;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
@@ -155,7 +156,7 @@ import com.android.server.display.layout.Layout;
import com.android.server.display.mode.DisplayModeDirector;
import com.android.server.display.utils.SensorUtils;
import com.android.server.input.InputManagerInternal;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
import com.android.server.wm.SurfaceAnimationThread;
import com.android.server.wm.WindowManagerInternal;
@@ -542,9 +543,9 @@ public final class DisplayManagerService extends SystemService {
mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
mUiHandler = UiThread.getHandler();
mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
- mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, mDisplayDeviceRepo,
- new LogicalDisplayListener(), mSyncRoot, mHandler,
- new FoldSettingWrapper(mContext.getContentResolver()));
+ mLogicalDisplayMapper = new LogicalDisplayMapper(mContext,
+ new FoldSettingProvider(mContext, new SettingsWrapper()), mDisplayDeviceRepo,
+ new LogicalDisplayListener(), mSyncRoot, mHandler);
mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
Resources resources = mContext.getResources();
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 59b887171506..e8a954ac8fc6 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -3519,7 +3519,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade,
int displayId, int displayState) {
- return new DisplayPowerState(blanker, colorFade, displayId, displayState);
+ return new DisplayPowerState(blanker, colorFade, displayId, displayState,
+ new Handler(/*async=*/ true));
}
DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps,
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 4db8777ba605..7558c6ab53c2 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -324,8 +324,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
// Must only be accessed on the handler thread.
private DisplayPowerState mPowerState;
-
-
// The currently active screen on unblocker. This field is non-null whenever
// we are waiting for a callback to release it and unblock the screen.
private ScreenOnUnblocker mPendingScreenOnUnblocker;
@@ -2884,7 +2882,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade,
int displayId, int displayState) {
- return new DisplayPowerState(blanker, colorFade, displayId, displayState);
+ return new DisplayPowerState(blanker, colorFade, displayId, displayState,
+ new Handler(/*async=*/ true));
}
DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps,
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 2c257a17af91..85c6a6de860f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -74,8 +74,9 @@ final class DisplayPowerState {
private volatile boolean mStopped;
DisplayPowerState(
- DisplayBlanker blanker, ColorFade colorFade, int displayId, int displayState) {
- mHandler = new Handler(true /*async*/);
+ DisplayBlanker blanker, ColorFade colorFade, int displayId, int displayState,
+ Handler handler) {
+ mHandler = handler;
mChoreographer = Choreographer.getInstance();
mBlanker = blanker;
mColorFade = colorFade;
@@ -317,6 +318,7 @@ final class DisplayPowerState {
mStopped = true;
mPhotonicModulator.interrupt();
dismissColorFade();
+ stopColorFade();
mCleanListener = null;
mHandler.removeCallbacksAndMessages(null);
}
@@ -376,6 +378,11 @@ final class DisplayPowerState {
}
}
+ // Clears up color fade resources.
+ private void stopColorFade() {
+ if (mColorFade != null) mColorFade.stop();
+ }
+
private final Runnable mScreenUpdateRunnable = new Runnable() {
@Override
public void run() {
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 26f8029cf5ac..f99c05179417 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -42,7 +42,7 @@ import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.layout.DisplayIdProducer;
import com.android.server.display.layout.Layout;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -143,7 +143,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
private final Listener mListener;
private final DisplayManagerService.SyncRoot mSyncRoot;
private final LogicalDisplayMapperHandler mHandler;
- private final FoldSettingWrapper mFoldSettingWrapper;
+ private final FoldSettingProvider mFoldSettingProvider;
private final PowerManager mPowerManager;
/**
@@ -189,25 +189,26 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
private boolean mBootCompleted = false;
private boolean mInteractive;
- LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+ LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
+ @NonNull DisplayDeviceRepository repo,
@NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
- @NonNull Handler handler, FoldSettingWrapper foldSettingWrapper) {
- this(context, repo, listener, syncRoot, handler,
+ @NonNull Handler handler) {
+ this(context, foldSettingProvider, repo, listener, syncRoot, handler,
new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY
- : sNextNonDefaultDisplayId++), foldSettingWrapper);
+ : sNextNonDefaultDisplayId++));
}
- LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+ LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
+ @NonNull DisplayDeviceRepository repo,
@NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
- @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap,
- FoldSettingWrapper foldSettingWrapper) {
+ @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap) {
mSyncRoot = syncRoot;
mPowerManager = context.getSystemService(PowerManager.class);
mInteractive = mPowerManager.isInteractive();
mHandler = new LogicalDisplayMapperHandler(handler.getLooper());
mDisplayDeviceRepo = repo;
mListener = listener;
- mFoldSettingWrapper = foldSettingWrapper;
+ mFoldSettingProvider = foldSettingProvider;
mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
mSupportsConcurrentInternalDisplays = context.getResources().getBoolean(
com.android.internal.R.bool.config_supportsConcurrentInternalDisplays);
@@ -479,10 +480,13 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
});
} else if (sleepDevice) {
// Send the device to sleep when required.
+ int goToSleepFlag =
+ mFoldSettingProvider.shouldSleepOnFold() ? 0
+ : PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP;
mHandler.post(() -> {
mPowerManager.goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD,
- PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP);
+ goToSleepFlag);
});
}
}
@@ -556,7 +560,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
&& mDeviceStatesOnWhichToSleep.get(pendingState)
&& !mDeviceStatesOnWhichToSleep.get(currentState)
&& !isOverrideActive
- && isInteractive && isBootCompleted && !mFoldSettingWrapper.shouldStayAwakeOnFold();
+ && isInteractive && isBootCompleted
+ && !mFoldSettingProvider.shouldStayAwakeOnFold();
}
private boolean areAllTransitioningDisplaysOffLocked() {
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index aa99dab8f007..7b613874e25e 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -235,6 +235,7 @@ final class HandwritingModeController {
@Nullable
HandwritingSession startHandwritingSession(
int requestId, int imePid, int imeUid, IBinder focusedWindowToken) {
+ clearPendingHandwritingDelegation();
if (mHandwritingSurface == null) {
Slog.e(TAG, "Cannot start handwriting session: Handwriting was not initialized.");
return null;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 6509126dcc60..7aea63255dc8 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -119,6 +119,7 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
+import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -126,6 +127,7 @@ import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.WindowManagerGlobal;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ImeTracker;
import android.view.inputmethod.InputBinding;
@@ -3072,7 +3074,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
"Waiting for the lazy init of mImeDrawsImeNavBarRes");
}
final boolean canImeDrawsImeNavBar =
- mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get();
+ mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get()
+ && hasNavigationBarOnCurrentDisplay();
final boolean shouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherLocked(
InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE);
return (canImeDrawsImeNavBar ? InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR : 0)
@@ -3080,6 +3083,21 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
? InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0);
}
+ /**
+ * Whether the current display has a navigation bar. When this is {@code false} (e.g. emulator),
+ * the IME should <em>not</em> draw the IME navigation bar.
+ */
+ @GuardedBy("ImfLock.class")
+ private boolean hasNavigationBarOnCurrentDisplay() {
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ try {
+ return wm.hasNavigationBar(mCurTokenDisplayId != INVALID_DISPLAY
+ ? mCurTokenDisplayId : DEFAULT_DISPLAY);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@GuardedBy("ImfLock.class")
private boolean shouldShowImeSwitcherLocked(int visibility) {
if (!mShowOngoingImeSwitcherForPhones) return false;
@@ -3359,15 +3377,18 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
} else {
// If subtype is null, try to find the most applicable one from
// getCurrentInputMethodSubtype.
+ subtypeId = NOT_A_SUBTYPE_ID;
newSubtype = getCurrentInputMethodSubtypeLocked();
+ if (newSubtype != null) {
+ for (int i = 0; i < subtypeCount; ++i) {
+ if (Objects.equals(newSubtype, info.getSubtypeAt(i))) {
+ subtypeId = i;
+ break;
+ }
+ }
+ }
}
- if (newSubtype == null || oldSubtype == null) {
- Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
- + ", new subtype = " + newSubtype);
- notifyInputMethodSubtypeChangedLocked(userId, info, null);
- return;
- }
- if (!newSubtype.equals(oldSubtype)) {
+ if (!Objects.equals(newSubtype, oldSubtype)) {
setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
IInputMethodInvoker curMethod = getCurMethodLocked();
if (curMethod != null) {
@@ -3432,13 +3453,19 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@Override
public void startStylusHandwriting(IInputMethodClient client) {
+ startStylusHandwriting(client, false /* usesDelegation */);
+ }
+
+ private void startStylusHandwriting(IInputMethodClient client, boolean usesDelegation) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.startStylusHandwriting");
try {
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#startStylusHandwriting");
int uid = Binder.getCallingUid();
synchronized (ImfLock.class) {
- mHwController.clearPendingHandwritingDelegation();
+ if (!usesDelegation) {
+ mHwController.clearPendingHandwritingDelegation();
+ }
if (!canInteractWithImeLocked(uid, client, "startStylusHandwriting",
null /* statsToken */)) {
return;
@@ -3520,7 +3547,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
return false;
}
- startStylusHandwriting(client);
+ startStylusHandwriting(client, true /* usesDelegation */);
return true;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index cab90d24ca39..f5c5867edb53 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2665,7 +2665,8 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private void setUserRestrictionInner(int userId, @NonNull String key, boolean value) {
+ @VisibleForTesting
+ void setUserRestrictionInner(int userId, @NonNull String key, boolean value) {
if (!UserRestrictionsUtils.isValidRestriction(key)) {
Slog.e(LOG_TAG, "Setting invalid restriction " + key);
return;
@@ -4273,11 +4274,11 @@ public class UserManagerService extends IUserManager.Stub {
UserRestrictionsUtils.writeRestrictions(serializer,
mDevicePolicyUserRestrictions.getRestrictions(UserHandle.USER_ALL),
- TAG_DEVICE_POLICY_RESTRICTIONS);
+ TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS);
UserRestrictionsUtils.writeRestrictions(serializer,
mDevicePolicyUserRestrictions.getRestrictions(userInfo.id),
- TAG_DEVICE_POLICY_RESTRICTIONS);
+ TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS);
}
if (userData.account != null) {
diff --git a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
index 4f221b532b75..97181948352b 100644
--- a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
@@ -244,6 +244,8 @@ public final class ConfigurationInternal {
&& mAutoDetectionEnabledSetting == that.mAutoDetectionEnabledSetting
&& mUserId == that.mUserId && mUserConfigAllowed == that.mUserConfigAllowed
&& mSystemClockUpdateThresholdMillis == that.mSystemClockUpdateThresholdMillis
+ && mSystemClockConfidenceThresholdMillis
+ == that.mSystemClockConfidenceThresholdMillis
&& mAutoSuggestionLowerBound.equals(that.mAutoSuggestionLowerBound)
&& mManualSuggestionLowerBound.equals(that.mManualSuggestionLowerBound)
&& mSuggestionUpperBound.equals(that.mSuggestionUpperBound)
@@ -253,7 +255,8 @@ public final class ConfigurationInternal {
@Override
public int hashCode() {
int result = Objects.hash(mAutoDetectionSupported, mAutoDetectionEnabledSetting, mUserId,
- mUserConfigAllowed, mSystemClockUpdateThresholdMillis, mAutoSuggestionLowerBound,
+ mUserConfigAllowed, mSystemClockUpdateThresholdMillis,
+ mSystemClockConfidenceThresholdMillis, mAutoSuggestionLowerBound,
mManualSuggestionLowerBound, mSuggestionUpperBound);
result = 31 * result + Arrays.hashCode(mOriginPriorities);
return result;
diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
index fc960d83dc3b..c52f8f887463 100644
--- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
@@ -22,15 +22,16 @@ import android.content.Context;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.server.AlarmManagerInternal;
import com.android.server.LocalServices;
import com.android.server.SystemClockTime;
import com.android.server.SystemClockTime.TimeConfidence;
-import com.android.server.timezonedetector.StateChangeListener;
-import java.io.PrintWriter;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Objects;
/**
@@ -41,14 +42,11 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
private static final String LOG_TAG = TimeDetectorService.TAG;
@NonNull private final Handler mHandler;
- @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final PowerManager.WakeLock mWakeLock;
@NonNull private final AlarmManagerInternal mAlarmManagerInternal;
- EnvironmentImpl(@NonNull Context context, @NonNull Handler handler,
- @NonNull ServiceConfigAccessor serviceConfigAccessor) {
+ EnvironmentImpl(@NonNull Context context, @NonNull Handler handler) {
mHandler = Objects.requireNonNull(handler);
- mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
PowerManager powerManager = context.getSystemService(PowerManager.class);
mWakeLock = Objects.requireNonNull(
@@ -59,19 +57,6 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
}
@Override
- public void setConfigurationInternalChangeListener(
- @NonNull StateChangeListener listener) {
- StateChangeListener stateChangeListener =
- () -> mHandler.post(listener::onChange);
- mServiceConfigAccessor.addConfigurationInternalChangeListener(stateChangeListener);
- }
-
- @Override
- public ConfigurationInternal getCurrentUserConfigurationInternal() {
- return mServiceConfigAccessor.getCurrentUserConfigurationInternal();
- }
-
- @Override
public void acquireWakeLock() {
if (mWakeLock.isHeld()) {
Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " already held");
@@ -126,8 +111,19 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
}
@Override
- public void dumpDebugLog(@NonNull PrintWriter printWriter) {
- SystemClockTime.dump(printWriter);
+ public void dumpDebugLog(@NonNull IndentingPrintWriter pw) {
+ long elapsedRealtimeMillis = elapsedRealtimeMillis();
+ pw.printf("elapsedRealtimeMillis()=%s (%s)\n",
+ Duration.ofMillis(elapsedRealtimeMillis), elapsedRealtimeMillis);
+ long systemClockMillis = systemClockMillis();
+ pw.printf("systemClockMillis()=%s (%s)\n",
+ Instant.ofEpochMilli(systemClockMillis), systemClockMillis);
+ pw.println("systemClockConfidence()=" + systemClockConfidence());
+
+ pw.println("SystemClockTime debug log:");
+ pw.increaseIndent();
+ SystemClockTime.dump(pw);
+ pw.decreaseIndent();
}
@Override
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 22f096b11f18..d88f4268434b 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -96,8 +96,8 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
CallerIdentityInjector callerIdentityInjector = CallerIdentityInjector.REAL;
TimeDetectorService service = new TimeDetectorService(
- context, handler, callerIdentityInjector, serviceConfigAccessor,
- timeDetectorStrategy, NtpTrustedTime.getInstance(context));
+ context, handler, callerIdentityInjector, timeDetectorStrategy,
+ NtpTrustedTime.getInstance(context));
// Publish the binder service so it can be accessed from other (appropriately
// permissioned) processes.
@@ -108,7 +108,6 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
@NonNull private final Handler mHandler;
@NonNull private final Context mContext;
@NonNull private final CallerIdentityInjector mCallerIdentityInjector;
- @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
@NonNull private final NtpTrustedTime mNtpTrustedTime;
@@ -123,20 +122,18 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
@VisibleForTesting
public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
@NonNull CallerIdentityInjector callerIdentityInjector,
- @NonNull ServiceConfigAccessor serviceConfigAccessor,
@NonNull TimeDetectorStrategy timeDetectorStrategy,
@NonNull NtpTrustedTime ntpTrustedTime) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
- mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
mNtpTrustedTime = Objects.requireNonNull(ntpTrustedTime);
- // Wire up a change listener so that ITimeZoneDetectorListeners can be notified when
- // the configuration changes for any reason.
- mServiceConfigAccessor.addConfigurationInternalChangeListener(
- () -> mHandler.post(this::handleConfigurationInternalChangedOnHandlerThread));
+ // Wire up a change listener so that ITimeDetectorListeners can be notified when the
+ // detector state changes for any reason.
+ mTimeDetectorStrategy.addChangeListener(
+ () -> mHandler.post(this::handleChangeOnHandlerThread));
}
@Override
@@ -151,10 +148,8 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- ConfigurationInternal configurationInternal =
- mServiceConfigAccessor.getConfigurationInternal(userId);
- final boolean bypassUserPolicyCheck = false;
- return configurationInternal.createCapabilitiesAndConfig(bypassUserPolicyCheck);
+ final boolean bypassUserPolicyChecks = false;
+ return mTimeDetectorStrategy.getCapabilitiesAndConfig(userId, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -180,9 +175,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
- final boolean bypassUserPolicyCheck = false;
- return mServiceConfigAccessor.updateConfiguration(
- resolvedUserId, configuration, bypassUserPolicyCheck);
+ final boolean bypassUserPolicyChecks = false;
+ return mTimeDetectorStrategy.updateConfiguration(
+ resolvedUserId, configuration, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
@@ -262,7 +257,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
}
}
- private void handleConfigurationInternalChangedOnHandlerThread() {
+ private void handleChangeOnHandlerThread() {
// Configuration has changed, but each user may have a different view of the configuration.
// It's possible that this will cause unnecessary notifications but that shouldn't be a
// problem.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 11cec6663a37..15c0a809cde8 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -21,6 +21,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
+import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
import android.app.time.TimeState;
import android.app.time.UnixEpochTime;
import android.app.timedetector.ManualTimeSuggestion;
@@ -87,6 +89,48 @@ public interface TimeDetectorStrategy extends Dumpable {
*/
boolean confirmTime(@NonNull UnixEpochTime confirmationTime);
+ /**
+ * Adds a listener that will be triggered when something changes that could affect the result
+ * of the {@link #getCapabilitiesAndConfig} call for the <em>current user only</em>. This
+ * includes the current user changing. This is exposed so that (indirect) users like SettingsUI
+ * can monitor for changes to data derived from {@link TimeCapabilitiesAndConfig} and update
+ * the UI accordingly.
+ */
+ void addChangeListener(@NonNull StateChangeListener listener);
+
+ /**
+ * Returns a {@link TimeCapabilitiesAndConfig} object for the specified user.
+ *
+ * <p>The strategy is dependent on device state like current user, settings and device config.
+ * These updates are usually handled asynchronously, so callers should expect some delay between
+ * a change being made directly to services like settings and the strategy becoming aware of
+ * them. Changes made via {@link #updateConfiguration} will be visible immediately.
+ *
+ * @param userId the user ID to retrieve the information for
+ * @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
+ * policy restrictions that should apply to actual users can be ignored
+ */
+ TimeCapabilitiesAndConfig getCapabilitiesAndConfig(
+ @UserIdInt int userId, boolean bypassUserPolicyChecks);
+
+ /**
+ * Updates the configuration properties that control a device's time behavior.
+ *
+ * <p>This method returns {@code true} if the configuration was changed, {@code false}
+ * otherwise.
+ *
+ * <p>See {@link #getCapabilitiesAndConfig} for guarantees about visibility of updates to
+ * subsequent calls.
+ *
+ * @param userId the current user ID, supplied to make sure that the asynchronous process
+ * that happens when users switch is completed when the call is made
+ * @param configuration the configuration changes
+ * @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
+ * policy restrictions that should apply to actual users can be ignored
+ */
+ boolean updateConfiguration(@UserIdInt int userId,
+ @NonNull TimeConfiguration configuration, boolean bypassUserPolicyChecks);
+
/** Processes the suggested time from telephony sources. */
void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion suggestion);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index b293bacfdc0d..fd35df61c952 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -30,6 +30,7 @@ import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
import android.app.time.TimeCapabilities;
import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
import android.app.time.TimeState;
import android.app.time.UnixEpochTime;
import android.app.timedetector.ManualTimeSuggestion;
@@ -48,10 +49,10 @@ import com.android.server.timezonedetector.ArrayMapWithHistory;
import com.android.server.timezonedetector.ReferenceWithHistory;
import com.android.server.timezonedetector.StateChangeListener;
-import java.io.PrintWriter;
-import java.time.Duration;
import java.time.Instant;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -94,6 +95,12 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
@NonNull
private final Environment mEnvironment;
+ @NonNull
+ private final ServiceConfigAccessor mServiceConfigAccessor;
+
+ @GuardedBy("this")
+ @NonNull private final List<StateChangeListener> mStateChangeListeners = new ArrayList<>();
+
@GuardedBy("this")
@NonNull
private ConfigurationInternal mCurrentConfigurationInternal;
@@ -139,16 +146,6 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
*/
public interface Environment {
- /**
- * Sets a {@link StateChangeListener} that will be invoked when there are any changes that
- * could affect the content of {@link ConfigurationInternal}.
- * This is invoked during system server setup.
- */
- void setConfigurationInternalChangeListener(@NonNull StateChangeListener listener);
-
- /** Returns the {@link ConfigurationInternal} for the current user. */
- @NonNull ConfigurationInternal getCurrentUserConfigurationInternal();
-
/** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
void acquireWakeLock();
@@ -174,16 +171,15 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
/** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */
void releaseWakeLock();
-
/**
* Adds a standalone entry to the time debug log.
*/
void addDebugLogEntry(@NonNull String logMsg);
/**
- * Dumps the time debug log to the supplied {@link PrintWriter}.
+ * Dumps the time debug log to the supplied {@link IndentingPrintWriter}.
*/
- void dumpDebugLog(PrintWriter printWriter);
+ void dumpDebugLog(IndentingPrintWriter ipw);
/**
* Requests that the supplied runnable is invoked asynchronously.
@@ -195,19 +191,23 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
@NonNull Context context, @NonNull Handler handler,
@NonNull ServiceConfigAccessor serviceConfigAccessor) {
- TimeDetectorStrategyImpl.Environment environment =
- new EnvironmentImpl(context, handler, serviceConfigAccessor);
- return new TimeDetectorStrategyImpl(environment);
+ TimeDetectorStrategyImpl.Environment environment = new EnvironmentImpl(context, handler);
+ return new TimeDetectorStrategyImpl(environment, serviceConfigAccessor);
}
@VisibleForTesting
- TimeDetectorStrategyImpl(@NonNull Environment environment) {
+ TimeDetectorStrategyImpl(@NonNull Environment environment,
+ @NonNull ServiceConfigAccessor serviceConfigAccessor) {
mEnvironment = Objects.requireNonNull(environment);
+ mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
synchronized (this) {
- mEnvironment.setConfigurationInternalChangeListener(
- this::handleConfigurationInternalChanged);
- mCurrentConfigurationInternal = mEnvironment.getCurrentUserConfigurationInternal();
+ // Listen for config and user changes and get an initial snapshot of configuration.
+ StateChangeListener stateChangeListener = this::handleConfigurationInternalMaybeChanged;
+ mServiceConfigAccessor.addConfigurationInternalChangeListener(stateChangeListener);
+
+ // Initialize mCurrentConfigurationInternal with a starting value.
+ updateCurrentConfigurationInternalIfRequired("TimeDetectorStrategyImpl:");
}
}
@@ -421,6 +421,57 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
}
+ @GuardedBy("this")
+ private void notifyStateChangeListenersAsynchronously() {
+ for (StateChangeListener listener : mStateChangeListeners) {
+ // This is queuing asynchronous notification, so no need to surrender the "this" lock.
+ mEnvironment.runAsync(listener::onChange);
+ }
+ }
+
+ @Override
+ public synchronized void addChangeListener(@NonNull StateChangeListener listener) {
+ mStateChangeListeners.add(listener);
+ }
+
+ @Override
+ public synchronized TimeCapabilitiesAndConfig getCapabilitiesAndConfig(@UserIdInt int userId,
+ boolean bypassUserPolicyChecks) {
+ ConfigurationInternal configurationInternal;
+ if (mCurrentConfigurationInternal.getUserId() == userId) {
+ // Use the cached snapshot we have.
+ configurationInternal = mCurrentConfigurationInternal;
+ } else {
+ // This is not a common case: It would be unusual to want the configuration for a user
+ // other than the "current" user, but it is supported because it is trivial to do so.
+ // Unlike the current user config, there's no cached copy to worry about so read it
+ // directly from mServiceConfigAccessor.
+ configurationInternal = mServiceConfigAccessor.getConfigurationInternal(userId);
+ }
+ return configurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks);
+ }
+
+ @Override
+ public synchronized boolean updateConfiguration(@UserIdInt int userId,
+ @NonNull TimeConfiguration configuration, boolean bypassUserPolicyChecks) {
+ // Write-through
+ boolean updateSuccessful = mServiceConfigAccessor.updateConfiguration(
+ userId, configuration, bypassUserPolicyChecks);
+
+ // The update above will trigger config update listeners asynchronously if they are needed,
+ // but that could mean an immediate call to getCapabilitiesAndConfig() for the current user
+ // wouldn't see the update. So, handle the cache update and notifications here. When the
+ // async update listener triggers it will find everything already up to date and do nothing.
+ if (updateSuccessful) {
+ String logMsg = "updateConfiguration:"
+ + " userId=" + userId
+ + ", configuration=" + configuration
+ + ", bypassUserPolicyChecks=" + bypassUserPolicyChecks;
+ updateCurrentConfigurationInternalIfRequired(logMsg);
+ }
+ return updateSuccessful;
+ }
+
@Override
public synchronized void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion suggestion) {
// Empty time suggestion means that telephony network connectivity has been lost.
@@ -448,26 +499,49 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
doAutoTimeDetection(reason);
}
- private synchronized void handleConfigurationInternalChanged() {
- ConfigurationInternal currentUserConfig =
- mEnvironment.getCurrentUserConfigurationInternal();
- String logMsg = "handleConfigurationInternalChanged:"
- + " oldConfiguration=" + mCurrentConfigurationInternal
- + ", newConfiguration=" + currentUserConfig;
- addDebugLogEntry(logMsg);
- mCurrentConfigurationInternal = currentUserConfig;
-
- boolean autoDetectionEnabled =
- mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior();
- // When automatic time detection is enabled we update the system clock instantly if we can.
- // Conversely, when automatic time detection is disabled we leave the clock as it is.
- if (autoDetectionEnabled) {
- String reason = "Auto time zone detection config changed.";
- doAutoTimeDetection(reason);
- } else {
- // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
- // it should be in future.
- mLastAutoSystemClockTimeSet = null;
+ /**
+ * Handles a configuration change notification.
+ */
+ private synchronized void handleConfigurationInternalMaybeChanged() {
+ String logMsg = "handleConfigurationInternalMaybeChanged:";
+ updateCurrentConfigurationInternalIfRequired(logMsg);
+ }
+
+ @GuardedBy("this")
+ private void updateCurrentConfigurationInternalIfRequired(@NonNull String logMsg) {
+ ConfigurationInternal newCurrentConfigurationInternal =
+ mServiceConfigAccessor.getCurrentUserConfigurationInternal();
+ // mCurrentConfigurationInternal is null the first time this method is called.
+ ConfigurationInternal oldCurrentConfigurationInternal = mCurrentConfigurationInternal;
+
+ // If the configuration actually changed, update the cached copy synchronously and do
+ // other necessary house-keeping / (async) listener notifications.
+ if (!newCurrentConfigurationInternal.equals(oldCurrentConfigurationInternal)) {
+ mCurrentConfigurationInternal = newCurrentConfigurationInternal;
+
+ logMsg = new StringBuilder(logMsg)
+ .append(" [oldConfiguration=").append(oldCurrentConfigurationInternal)
+ .append(", newConfiguration=").append(newCurrentConfigurationInternal)
+ .append("]")
+ .toString();
+ addDebugLogEntry(logMsg);
+
+ // The configuration and maybe the status changed so notify listeners.
+ notifyStateChangeListenersAsynchronously();
+
+ boolean autoDetectionEnabled =
+ mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior();
+ // When automatic time detection is enabled we update the system clock instantly if we
+ // can. Conversely, when automatic time detection is disabled we leave the clock as it
+ // is.
+ if (autoDetectionEnabled) {
+ String reason = "Auto time zone detection config changed.";
+ doAutoTimeDetection(reason);
+ } else {
+ // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict
+ // what it should be in future.
+ mLastAutoSystemClockTimeSet = null;
+ }
}
}
@@ -489,13 +563,11 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
ipw.println("[Capabilities="
+ mCurrentConfigurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks)
+ "]");
- long elapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
- ipw.printf("mEnvironment.elapsedRealtimeMillis()=%s (%s)\n",
- Duration.ofMillis(elapsedRealtimeMillis), elapsedRealtimeMillis);
- long systemClockMillis = mEnvironment.systemClockMillis();
- ipw.printf("mEnvironment.systemClockMillis()=%s (%s)\n",
- Instant.ofEpochMilli(systemClockMillis), systemClockMillis);
- ipw.println("mEnvironment.systemClockConfidence()=" + mEnvironment.systemClockConfidence());
+
+ ipw.println("mEnvironment:");
+ ipw.increaseIndent();
+ mEnvironment.dumpDebugLog(ipw);
+ ipw.decreaseIndent();
ipw.println("Time change log:");
ipw.increaseIndent(); // level 2
@@ -525,6 +597,11 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
ipw.decreaseIndent(); // level 1
}
+ @VisibleForTesting
+ public synchronized ConfigurationInternal getCachedCapabilitiesAndConfigForTests() {
+ return mCurrentConfigurationInternal;
+ }
+
@GuardedBy("this")
private boolean storeTelephonySuggestion(@NonNull TelephonyTimeSuggestion suggestion) {
UnixEpochTime newUnixEpochTime = suggestion.getUnixEpochTime();
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 01fdc8800c0e..7862f58374a3 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -41,6 +41,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
@@ -62,6 +63,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -1304,6 +1306,46 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub implements
return false;
}
+ /**
+ * Check if the targetPkg can be granted permission to access uri by
+ * the callingUid using the given modeFlags. See {@link #checkGrantUriPermissionUnlocked}.
+ *
+ * @param callingUid The uid of the grantor app that has permissions to the uri.
+ * @param targetPkg The package name of the granted app that needs permissions to the uri.
+ * @param uri The uri for which permissions should be granted.
+ * @param modeFlags The modes to grant. See {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, etc.
+ * @param userId The userId in which the uri is to be resolved.
+ * @return uid of the target or -1 if permission grant not required. Returns -1 if the caller
+ * does not hold INTERACT_ACROSS_USERS_FULL
+ * @throws SecurityException if the grant is not allowed.
+ */
+ @Override
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ public int checkGrantUriPermission_ignoreNonSystem(int callingUid, String targetPkg, Uri uri,
+ int modeFlags, int userId) {
+ if (!isCallerIsSystemOrPrivileged()) {
+ return Process.INVALID_UID;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ return checkGrantUriPermissionUnlocked(callingUid, targetPkg, uri, modeFlags,
+ userId);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ private boolean isCallerIsSystemOrPrivileged() {
+ final int uid = Binder.getCallingUid();
+ if (uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) {
+ return true;
+ }
+ return ActivityManager.checkComponentPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ uid, /* owningUid = */-1, /* exported = */ true)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
@Override
public ArrayList<UriPermission> providePersistentUriGrants() {
final ArrayList<UriPermission> result = new ArrayList<>();
diff --git a/services/core/java/com/android/server/utils/FoldSettingProvider.java b/services/core/java/com/android/server/utils/FoldSettingProvider.java
new file mode 100644
index 000000000000..d62628b73019
--- /dev/null
+++ b/services/core/java/com/android/server/utils/FoldSettingProvider.java
@@ -0,0 +1,102 @@
+/*
+ * 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.utils;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.util.SettingsWrapper;
+
+import java.util.Set;
+
+/**
+ * This class provides a convenient way to access the {@link Settings.System#FOLD_LOCK_BEHAVIOR}.
+ * The {@link Settings.System#FOLD_LOCK_BEHAVIOR} setting controls the behavior of the device when
+ * it is folded, and provides the user with three different options to choose from. Those are:
+ * 1. Stay awake on fold: The device will remain unlocked when it is folded.
+ * 2. Selective stay awake: The device will remain unlocked when it is folded only if there are
+ * apps with wakelocks running. This is also the set default behavior.
+ * 3. Sleep on fold: The device will lock when it is folded, regardless of which apps are running
+ * or whether any wakelocks are held.
+ *
+ * Keep the setting values in this class in sync with the values in
+ * {@link com.android.settings.display.FoldLockBehaviorSettings}
+ */
+public class FoldSettingProvider {
+
+ public static final String SETTING_VALUE_STAY_AWAKE_ON_FOLD = "stay_awake_on_fold_key";
+ public static final String SETTING_VALUE_SELECTIVE_STAY_AWAKE = "selective_stay_awake_key";
+ public static final String SETTING_VALUE_SLEEP_ON_FOLD = "sleep_on_fold_key";
+ private static final String SETTING_VALUE_DEFAULT = SETTING_VALUE_SELECTIVE_STAY_AWAKE;
+ private static final Set<String> SETTING_VALUES = Set.of(SETTING_VALUE_STAY_AWAKE_ON_FOLD,
+ SETTING_VALUE_SELECTIVE_STAY_AWAKE, SETTING_VALUE_SLEEP_ON_FOLD);
+ private static final String TAG = "FoldSettingProvider";
+
+ private final ContentResolver mContentResolver;
+ private final boolean mIsFoldLockBehaviorAvailable;
+ private final SettingsWrapper mSettingsWrapper;
+
+ public FoldSettingProvider(Context context, SettingsWrapper settingsWrapper) {
+ mContentResolver = context.getContentResolver();
+ mSettingsWrapper = settingsWrapper;
+ mIsFoldLockBehaviorAvailable = context.getResources().getBoolean(
+ R.bool.config_fold_lock_behavior);
+ }
+
+ /**
+ * Returns whether the device should remain awake after folding.
+ */
+ public boolean shouldStayAwakeOnFold() {
+ return getFoldSettingValue().equals(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+ }
+
+ /**
+ * Returns whether the device should selective remain awake after folding.
+ */
+ public boolean shouldSelectiveStayAwakeOnFold() {
+ return getFoldSettingValue().equals(SETTING_VALUE_SELECTIVE_STAY_AWAKE);
+ }
+
+ /**
+ * Returns whether the device should strictly sleep after folding.
+ */
+ public boolean shouldSleepOnFold() {
+ return getFoldSettingValue().equals(SETTING_VALUE_SLEEP_ON_FOLD);
+ }
+
+ private String getFoldSettingValue() {
+ if (!mIsFoldLockBehaviorAvailable) {
+ return SETTING_VALUE_DEFAULT;
+ }
+ String foldSettingValue = mSettingsWrapper.getStringForUser(
+ mContentResolver,
+ Settings.System.FOLD_LOCK_BEHAVIOR,
+ UserHandle.USER_CURRENT);
+ foldSettingValue = (foldSettingValue != null) ? foldSettingValue : SETTING_VALUE_DEFAULT;
+ if (!SETTING_VALUES.contains(foldSettingValue)) {
+ Log.e(TAG,
+ "getFoldSettingValue: Invalid setting value, returning default setting value");
+ foldSettingValue = SETTING_VALUE_DEFAULT;
+ }
+
+ return foldSettingValue;
+ }
+}
diff --git a/services/core/java/com/android/server/utils/FoldSettingWrapper.java b/services/core/java/com/android/server/utils/FoldSettingWrapper.java
deleted file mode 100644
index 97a1ac06e24c..000000000000
--- a/services/core/java/com/android/server/utils/FoldSettingWrapper.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.utils;
-
-import android.content.ContentResolver;
-import android.provider.Settings;
-
-/**
- * A wrapper class for the {@link Settings.System#STAY_AWAKE_ON_FOLD} setting.
- *
- * This class provides a convenient way to access the {@link Settings.System#STAY_AWAKE_ON_FOLD}
- * setting for testing.
- */
-public class FoldSettingWrapper {
- private final ContentResolver mContentResolver;
-
- public FoldSettingWrapper(ContentResolver contentResolver) {
- mContentResolver = contentResolver;
- }
-
- /**
- * Returns whether the device should remain awake after folding.
- */
- public boolean shouldStayAwakeOnFold() {
- try {
- return (Settings.System.getIntForUser(
- mContentResolver,
- Settings.System.STAY_AWAKE_ON_FOLD,
- 0) == 1);
- } catch (Settings.SettingNotFoundException e) {
- return false;
- }
- }
-}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 309a9c0e0372..5b25e890aaa2 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -321,9 +321,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (DEBUG) {
Slog.d(TAG, "publish system wallpaper changed!");
}
- if (localSync != null) {
- localSync.complete();
- }
notifyWallpaperChanged(wallpaper);
}
};
@@ -331,7 +328,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
// If this was the system wallpaper, rebind...
bindWallpaperComponentLocked(mImageWallpaper, true, false, wallpaper,
callback);
- notifyColorsWhich |= FLAG_SYSTEM;
+ notifyColorsWhich |= wallpaper.mWhich;
}
if (lockWallpaperChanged) {
@@ -345,9 +342,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (DEBUG) {
Slog.d(TAG, "publish lock wallpaper changed!");
}
- if (localSync != null) {
- localSync.complete();
- }
notifyWallpaperChanged(wallpaper);
}
};
@@ -372,9 +366,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
saveSettingsLocked(wallpaper.userId);
- // Notify the client immediately if only lockscreen wallpaper changed.
- if (lockWallpaperChanged && !sysWallpaperChanged) {
- notifyWallpaperChanged(wallpaper);
+ if ((sysWallpaperChanged || lockWallpaperChanged) && localSync != null) {
+ localSync.complete();
}
}
@@ -1383,7 +1376,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
lockWp.connection.mWallpaper = lockWp;
mOriginalSystem.mWhich = FLAG_LOCK;
updateEngineFlags(mOriginalSystem);
- notifyWallpaperColorsChanged(lockWp, FLAG_LOCK);
} else {
// Failed rename, use current system wp for both
if (DEBUG) {
@@ -1403,7 +1395,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
updateEngineFlags(mOriginalSystem);
mLockWallpaperMap.put(mNewWallpaper.userId, mOriginalSystem);
mLastLockWallpaper = mOriginalSystem;
- notifyWallpaperColorsChanged(mOriginalSystem, FLAG_LOCK);
}
} else if (mNewWallpaper.mWhich == FLAG_LOCK) {
// New wp is lock only, so old system+lock is now system only
@@ -1417,10 +1408,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
}
-
- synchronized (mLock) {
- saveSettingsLocked(mNewWallpaper.userId);
- }
+ saveSettingsLocked(mNewWallpaper.userId);
if (DEBUG) {
Slog.v(TAG, "--- wallpaper changed --");
@@ -3300,7 +3288,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (DEBUG) {
Slog.d(TAG, "publish system wallpaper changed!");
}
- liveSync.complete();
}
};
@@ -3356,6 +3343,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
mLockWallpaperMap.remove(newWallpaper.userId);
}
+ if (liveSync != null) liveSync.complete();
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -3474,6 +3462,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
// Has the component changed?
if (!force && changingToSame(componentName, wallpaper)) {
+ try {
+ if (reply != null) reply.sendResult(null);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to send callback", e);
+ }
return true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index aafff2c70b8b..a70f339ec168 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1162,9 +1162,7 @@ class ActivityClientController extends IActivityClientController.Stub {
fullscreenRequest, r);
reportMultiwindowFullscreenRequestValidatingResult(callback, validateResult);
if (validateResult != RESULT_APPROVED) {
- if (queued) {
- transition.abort();
- }
+ transition.abort();
return;
}
transition.collect(topFocusedRootTask);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ff2c71999188..0a332a3683c5 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3643,6 +3643,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
if (r.getParent() == null) {
Slog.e(TAG, "Skip enterPictureInPictureMode, destroyed " + r);
+ if (transition != null) {
+ transition.abort();
+ }
return;
}
EventLogTags.writeWmEnterPip(r.mUserId, System.identityHashCode(r),
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 5aa7c97ecb08..7cd07d6f3a5f 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -35,6 +35,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.DeviceConfig;
import android.view.ContentRecordingSession;
+import android.view.ContentRecordingSession.RecordContent;
import android.view.Display;
import android.view.SurfaceControl;
@@ -84,6 +85,7 @@ final class ContentRecorder implements WindowContainerListener {
/**
* The last configuration orientation.
*/
+ @Configuration.Orientation
private int mLastOrientation = ORIENTATION_UNDEFINED;
ContentRecorder(@NonNull DisplayContent displayContent) {
@@ -149,6 +151,20 @@ final class ContentRecorder implements WindowContainerListener {
return;
}
+ // TODO(b/297514518) Do not start capture if the app is in PIP, the bounds are
+ // inaccurate.
+ if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) {
+ final Task capturedTask = mRecordedWindowContainer.asTask();
+ if (capturedTask.inPinnedWindowingMode()) {
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Content Recording: Display %d was already recording, but "
+ + "pause capture since the task is in PIP",
+ mDisplayContent.getDisplayId());
+ pauseRecording();
+ return;
+ }
+ }
+
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: Display %d was already recording, so apply "
+ "transformations if necessary",
@@ -156,7 +172,8 @@ final class ContentRecorder implements WindowContainerListener {
// Retrieve the size of the region to record, and continue with the update
// if the bounds or orientation has changed.
final Rect recordedContentBounds = mRecordedWindowContainer.getBounds();
- int recordedContentOrientation = mRecordedWindowContainer.getOrientation();
+ @Configuration.Orientation int recordedContentOrientation =
+ mRecordedWindowContainer.getConfiguration().orientation;
if (!mLastRecordedBounds.equals(recordedContentBounds)
|| lastOrientation != recordedContentOrientation) {
Point surfaceSize = fetchSurfaceSizeIfPresent();
@@ -289,6 +306,17 @@ final class ContentRecorder implements WindowContainerListener {
return;
}
+ // TODO(b/297514518) Do not start capture if the app is in PIP, the bounds are inaccurate.
+ if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) {
+ if (mRecordedWindowContainer.asTask().inPinnedWindowingMode()) {
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Content Recording: Display %d should start recording, but "
+ + "don't yet since the task is in PIP",
+ mDisplayContent.getDisplayId());
+ return;
+ }
+ }
+
final Point surfaceSize = fetchSurfaceSizeIfPresent();
if (surfaceSize == null) {
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
@@ -302,9 +330,6 @@ final class ContentRecorder implements WindowContainerListener {
+ "state %d",
mDisplayContent.getDisplayId(), mDisplayContent.getDisplayInfo().state);
- // TODO(b/274790702): Do not start recording if waiting for consent - for now,
- // go ahead.
-
// Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
mRecordedSurface = SurfaceControl.mirrorSurface(
mRecordedWindowContainer.getSurfaceControl());
@@ -356,7 +381,7 @@ final class ContentRecorder implements WindowContainerListener {
*/
@Nullable
private WindowContainer retrieveRecordedWindowContainer() {
- final int contentToRecord = mContentRecordingSession.getContentToRecord();
+ @RecordContent final int contentToRecord = mContentRecordingSession.getContentToRecord();
final IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
switch (contentToRecord) {
case RECORD_CONTENT_DISPLAY:
@@ -472,6 +497,12 @@ final class ContentRecorder implements WindowContainerListener {
shiftedY = (surfaceSize.y - scaledHeight) / 2;
}
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Content Recording: Apply transformations of shift %d x %d, scale %f, crop %d x "
+ + "%d for display %d",
+ shiftedX, shiftedY, scale, recordedContentBounds.width(),
+ recordedContentBounds.height(), mDisplayContent.getDisplayId());
+
transaction
// Crop the area to capture to exclude the 'extra' wallpaper that is used
// for parallax (b/189930234).
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 354b0db77382..119055ae6770 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR;
import static android.view.Display.TYPE_INTERNAL;
import static android.view.InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE;
import static android.view.InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS;
@@ -268,6 +269,8 @@ public class DisplayPolicy {
private boolean mIsFreeformWindowOverlappingWithNavBar;
+ private @InsetsType int mForciblyShownTypes;
+
private boolean mIsImmersiveMode;
// The windows we were told about in focusChanged.
@@ -1201,8 +1204,8 @@ public class DisplayPolicy {
throw new IllegalArgumentException("IME insets must be provided by a window.");
}
- if (mNavigationBar != null && navigationBarPosition(displayFrames.mRotation)
- == NAV_BAR_BOTTOM) {
+ if (!ENABLE_HIDE_IME_CAPTION_BAR && mNavigationBar != null
+ && navigationBarPosition(displayFrames.mRotation) == NAV_BAR_BOTTOM) {
// In gesture navigation, nav bar frame is larger than frame to calculate insets.
// IME should not provide frame which is smaller than the nav bar frame. Otherwise,
// nav bar might be overlapped with the content of the client when IME is shown.
@@ -1401,6 +1404,7 @@ public class DisplayPolicy {
mAllowLockscreenWhenOn = false;
mShowingDream = false;
mIsFreeformWindowOverlappingWithNavBar = false;
+ mForciblyShownTypes = 0;
}
/**
@@ -1458,6 +1462,10 @@ public class DisplayPolicy {
}
}
+ if (win.mSession.mCanForceShowingInsets) {
+ mForciblyShownTypes |= win.mAttrs.forciblyShownTypes;
+ }
+
if (!affectsSystemUi) {
return;
}
@@ -1639,6 +1647,10 @@ public class DisplayPolicy {
mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
}
+ boolean areTypesForciblyShownTransiently(@InsetsType int types) {
+ return (mForciblyShownTypes & types) == types;
+ }
+
/**
* Applies the keyguard policy to a specific window.
*
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 835c92d0a30d..d0d7f493b969 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -23,8 +23,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.InsetsSource.ID_IME;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import android.annotation.NonNull;
@@ -77,6 +75,18 @@ class InsetsPolicy {
/** Used to show system bars permanently. This will affect the layout. */
private final InsetsControlTarget mPermanentControlTarget;
+ /**
+ * Used to override the visibility of {@link Type#statusBars()} when dispatching insets to
+ * clients.
+ */
+ private InsetsControlTarget mFakeStatusControlTarget;
+
+ /**
+ * Used to override the visibility of {@link Type#navigationBars()} when dispatching insets to
+ * clients.
+ */
+ private InsetsControlTarget mFakeNavControlTarget;
+
private WindowState mFocusedWin;
private final BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
private final BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
@@ -103,25 +113,25 @@ class InsetsPolicy {
abortTransient();
}
mFocusedWin = focusedWin;
+ final WindowState notificationShade = mPolicy.getNotificationShade();
+ final WindowState topApp = mPolicy.getTopFullscreenOpaqueWindow();
final InsetsControlTarget statusControlTarget =
getStatusControlTarget(focusedWin, false /* fake */);
+ mFakeStatusControlTarget = statusControlTarget == mTransientControlTarget
+ ? getStatusControlTarget(focusedWin, true /* fake */)
+ : statusControlTarget == notificationShade
+ ? getStatusControlTarget(topApp, true /* fake */)
+ : null;
final InsetsControlTarget navControlTarget =
getNavControlTarget(focusedWin, false /* fake */);
- final WindowState notificationShade = mPolicy.getNotificationShade();
- final WindowState topApp = mPolicy.getTopFullscreenOpaqueWindow();
+ mFakeNavControlTarget = navControlTarget == mTransientControlTarget
+ ? getNavControlTarget(focusedWin, true /* fake */)
+ : navControlTarget == notificationShade
+ ? getNavControlTarget(topApp, true /* fake */)
+ : null;
mStateController.onBarControlTargetChanged(
- statusControlTarget,
- statusControlTarget == mTransientControlTarget
- ? getStatusControlTarget(focusedWin, true /* fake */)
- : statusControlTarget == notificationShade
- ? getStatusControlTarget(topApp, true /* fake */)
- : null,
- navControlTarget,
- navControlTarget == mTransientControlTarget
- ? getNavControlTarget(focusedWin, true /* fake */)
- : navControlTarget == notificationShade
- ? getNavControlTarget(topApp, true /* fake */)
- : null);
+ statusControlTarget, mFakeStatusControlTarget,
+ navControlTarget, mFakeNavControlTarget);
mStatusBar.updateVisibility(statusControlTarget, Type.statusBars());
mNavBar.updateVisibility(navControlTarget, Type.navigationBars());
}
@@ -206,7 +216,7 @@ class InsetsPolicy {
boolean includesTransient) {
InsetsState state;
if (!includesTransient) {
- state = adjustVisibilityForTransientTypes(originalState);
+ state = adjustVisibilityForFakeControllingSources(originalState);
} else {
state = originalState;
}
@@ -321,24 +331,40 @@ class InsetsPolicy {
return state;
}
- private InsetsState adjustVisibilityForTransientTypes(InsetsState originalState) {
+ private InsetsState adjustVisibilityForFakeControllingSources(InsetsState originalState) {
+ if (mFakeStatusControlTarget == null && mFakeNavControlTarget == null) {
+ return originalState;
+ }
InsetsState state = originalState;
for (int i = state.sourceSize() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
- if (isTransient(source.getType()) && source.isVisible()) {
- if (state == originalState) {
- // The source will be modified, create a non-deep copy to store the new one.
- state = new InsetsState(originalState);
- }
- // Replace the source with a copy in invisible state.
- final InsetsSource outSource = new InsetsSource(source);
- outSource.setVisible(false);
- state.addSource(outSource);
- }
+ state = adjustVisibilityForFakeControllingSource(state, Type.statusBars(), source,
+ mFakeStatusControlTarget);
+ state = adjustVisibilityForFakeControllingSource(state, Type.navigationBars(), source,
+ mFakeNavControlTarget);
}
return state;
}
+ private static InsetsState adjustVisibilityForFakeControllingSource(InsetsState originalState,
+ @InsetsType int type, InsetsSource source, InsetsControlTarget target) {
+ if (source.getType() != type || target == null) {
+ return originalState;
+ }
+ final boolean isRequestedVisible = target.isRequestedVisible(type);
+ if (source.isVisible() == isRequestedVisible) {
+ return originalState;
+ }
+ // The source will be modified, create a non-deep copy to store the new one.
+ final InsetsState state = new InsetsState(originalState);
+
+ // Replace the source with a copy with the overridden visibility.
+ final InsetsSource outSource = new InsetsSource(source);
+ outSource.setVisible(isRequestedVisible);
+ state.addSource(outSource);
+ return state;
+ }
+
private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
boolean copyState) {
if (w.mIsImWindow) {
@@ -473,7 +499,7 @@ class InsetsPolicy {
// we will dispatch the real visibility of status bar to the client.
return mPermanentControlTarget;
}
- if (forceShowsStatusBarTransiently() && !fake) {
+ if (mPolicy.areTypesForciblyShownTransiently(Type.statusBars()) && !fake) {
// Status bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
@@ -505,7 +531,7 @@ class InsetsPolicy {
if (imeWin != null && imeWin.isVisible() && !mHideNavBarForKeyboard) {
// Force showing navigation bar while IME is visible and if navigation bar is not
// configured to be hidden by the IME.
- return null;
+ return mPermanentControlTarget;
}
if (!fake && isTransient(Type.navigationBars())) {
return mTransientControlTarget;
@@ -533,7 +559,7 @@ class InsetsPolicy {
// bar, and we will dispatch the real visibility of navigation bar to the client.
return mPermanentControlTarget;
}
- if (forceShowsNavigationBarTransiently() && !fake) {
+ if (mPolicy.areTypesForciblyShownTransiently(Type.navigationBars()) && !fake) {
// Navigation bar is forcibly shown transiently, and its new visibility won't be
// dispatched to the client so that we can keep the layout stable. We will dispatch the
// fake control to the client, so that it can re-show the bar during this scenario.
@@ -603,17 +629,6 @@ class InsetsPolicy {
&& focusedWin.getAttrs().type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
}
- private boolean forceShowsStatusBarTransiently() {
- final WindowState win = mPolicy.getStatusBar();
- return win != null && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
- }
-
- private boolean forceShowsNavigationBarTransiently() {
- final WindowState win = mPolicy.getNotificationShade();
- return win != null
- && (win.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
- }
-
private void dispatchTransientSystemBarsVisibilityChanged(
@Nullable WindowState focusedWindow,
boolean areVisible,
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 97b3e3280f2b..45cf10bd3f5e 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -80,10 +80,10 @@ final class LetterboxConfiguration {
// Whether per-app user aspect ratio override settings is enabled
private static final String KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS =
- "enable_app_compat_user_aspect_ratio_settings";
+ "enable_app_compat_aspect_ratio_user_settings";
// TODO(b/288142656): Enable user aspect ratio settings by default.
- private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = false;
+ private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = true;
// Whether per-app fullscreen user aspect ratio override option is enabled
private static final String KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN =
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index b49c5fb2c25d..2bc701000398 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -22,6 +22,7 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION;
import static android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.STATUS_BAR_SERVICE;
import static android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
@@ -107,6 +108,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
private final ArraySet<WindowSurfaceController> mAlertWindowSurfaces = new ArraySet<>();
private final DragDropController mDragDropController;
final boolean mCanAddInternalSystemWindow;
+ boolean mCanForceShowingInsets;
private final boolean mCanStartTasksFromRecents;
final boolean mCanCreateSystemApplicationOverlay;
@@ -129,6 +131,9 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
+ mCanForceShowingInsets = service.mAtmService.isCallerRecents(mUid)
+ || service.mContext.checkCallingOrSelfPermission(STATUS_BAR_SERVICE)
+ == PERMISSION_GRANTED;
mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission(
HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED
|| service.mContext.checkCallingOrSelfPermission(HIDE_OVERLAY_WINDOWS)
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index c49a1d0bf19d..f8736e764a6e 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1486,6 +1486,11 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
return;
}
+ if (mState != STATE_STARTED) {
+ Slog.e(TAG, "Playing a Transition which hasn't started! #" + mSyncId + " This will "
+ + "likely cause an exception in Shell");
+ }
+
mState = STATE_PLAYING;
mStartTransaction = transaction;
mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 75458302586d..034299659dd5 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -1147,7 +1147,7 @@ class TransitionController {
Transition.asyncTraceBegin("animating", 0x41bfaf1 /* hashcode of TAG */);
} else if (!animatingState && mAnimatingState) {
t.setEarlyWakeupEnd();
- mAtm.mWindowManager.requestTraversal();
+ mAtm.mWindowManager.scheduleAnimationLocked();
mSnapshotController.setPause(false);
mAnimatingState = false;
Transition.asyncTraceEnd(0x41bfaf1 /* hashcode of TAG */);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b1041855a2dc..9515b7958355 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -241,6 +241,7 @@ import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
import static android.provider.Telephony.Carriers.INVALID_APN_ID;
import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTATION;
+
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -11279,25 +11280,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- private void dumpPerUserData(IndentingPrintWriter pw) {
+ private void dumpPersonalAppInfoForSystemUserNoLock(IndentingPrintWriter pw) {
+ wtfIfInLock();
+ PersonalAppsSuspensionHelper.forUser(mContext, UserHandle.USER_SYSTEM).dump(pw);
+ }
+
+ private void dumpPerUserPolicyData(IndentingPrintWriter pw) {
int userCount = mUserData.size();
for (int i = 0; i < userCount; i++) {
int userId = mUserData.keyAt(i);
DevicePolicyData policy = getUserData(userId);
policy.dump(pw);
pw.println();
-
- if (userId == UserHandle.USER_SYSTEM) {
- pw.increaseIndent();
- PersonalAppsSuspensionHelper.forUser(mContext, userId).dump(pw);
- pw.decreaseIndent();
- pw.println();
- } else {
- // pm.getUnsuspendablePackages() will fail if it's called for a different user;
- // as this dump is mostly useful for system user anyways, we can just ignore the
- // others (rather than changing the permission check in the PM method)
- Slogf.d(LOG_TAG, "skipping PersonalAppsSuspensionHelper.dump() for user " + userId);
- }
}
}
@@ -11315,7 +11309,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
pw.println();
mDeviceAdminServiceController.dump(pw);
pw.println();
- dumpPerUserData(pw);
+ dumpPerUserPolicyData(pw);
pw.println();
mConstants.dump(pw);
pw.println();
@@ -11342,6 +11336,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mStateCache.dump(pw);
pw.println();
}
+ dumpPersonalAppInfoForSystemUserNoLock(pw);
synchronized (mSubscriptionsChangedListenerLock) {
pw.println("Subscription changed listener : " + mSubscriptionsChangedListener);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
index 9a8e421d5d12..8684dbe73947 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -111,7 +111,7 @@ public class RemoteBugreportManager {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ cancelNotification();
if (ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
onBugreportSharingAccepted();
} else if (ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
@@ -213,8 +213,7 @@ public class RemoteBugreportManager {
mRemoteBugreportServiceIsActive.set(true);
mRemoteBugreportSharingAccepted.set(false);
registerRemoteBugreportReceivers();
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
- buildNotification(NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
+ notify(NOTIFICATION_BUGREPORT_STARTED);
mHandler.postDelayed(mRemoteBugreportTimeoutRunnable, REMOTE_BUGREPORT_TIMEOUT_MILLIS);
return true;
} catch (RemoteException re) {
@@ -258,13 +257,10 @@ public class RemoteBugreportManager {
final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
if (mRemoteBugreportSharingAccepted.get()) {
shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().cancel(LOG_TAG,
- NOTIFICATION_ID);
+ cancelNotification();
} else {
mService.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
- buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
- UserHandle.ALL);
+ notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED);
}
mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
}
@@ -274,7 +270,7 @@ public class RemoteBugreportManager {
mInjector.systemPropertiesSet(CTL_STOP, REMOTE_BUGREPORT_SERVICE);
mRemoteBugreportSharingAccepted.set(false);
mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ cancelNotification();
final Bundle extras = new Bundle();
extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
@@ -289,9 +285,7 @@ public class RemoteBugreportManager {
if (uriAndHash != null) {
shareBugreportWithDeviceOwnerIfExists(uriAndHash.first, uriAndHash.second);
} else if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
- buildNotification(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
- UserHandle.ALL);
+ notify(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED);
}
}
@@ -340,7 +334,16 @@ public class RemoteBugreportManager {
filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
- buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED), UserHandle.ALL);
+ notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED);
+ }
+
+ private void notify(@RemoteBugreportNotificationType int type) {
+ mInjector.getNotificationManager()
+ .notifyAsUser(LOG_TAG, NOTIFICATION_ID, buildNotification(type), UserHandle.ALL);
+ }
+
+ private void cancelNotification() {
+ mInjector.getNotificationManager()
+ .cancelAsUser(LOG_TAG, NOTIFICATION_ID, UserHandle.ALL);
}
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index e8acb067f625..6ff7b2601b79 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -16,15 +16,20 @@
package com.android.inputmethodservice;
+import static android.view.WindowInsets.Type.captionBar;
+
import static com.android.compatibility.common.util.SystemUtil.eventually;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
import android.app.Instrumentation;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Insets;
import android.os.RemoteException;
import android.provider.Settings;
import android.support.test.uiautomator.By;
@@ -32,6 +37,7 @@ import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.util.Log;
+import android.view.WindowManagerGlobal;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
@@ -592,6 +598,20 @@ public class InputMethodServiceTest {
false /* orientationPortrait */);
}
+ /**
+ * This checks that when the system navigation bar is not created (e.g. emulator),
+ * then the IME caption bar is also not created.
+ */
+ @Test
+ public void testNoNavigationBar_thenImeNoCaptionBar() throws Exception {
+ boolean hasNavigationBar = WindowManagerGlobal.getWindowManagerService()
+ .hasNavigationBar(mInputMethodService.getDisplayId());
+ assumeFalse("Must not have a navigation bar", hasNavigationBar);
+
+ assertEquals(Insets.NONE, mInputMethodService.getWindow().getWindow().getDecorView()
+ .getRootWindowInsets().getInsetsIgnoringVisibility(captionBar()));
+ }
+
private void verifyInputViewStatus(
Runnable runnable, boolean expected, boolean inputViewStarted)
throws InterruptedException {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
index c39bb56e7ba1..9d309e9a9433 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -1104,6 +1104,21 @@ public final class DisplayPowerController2Test {
verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true);
}
+ @Test
+ public void testPowerStateStopsOnDpcStop() {
+ // Set up
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1);
+
+ // Stop dpc
+ mHolder.dpc.stop();
+ advanceTime(1);
+
+ // Ensure dps has stopped
+ verify(mHolder.displayPowerState, times(1)).stop();
+ }
+
/**
* Creates a mock and registers it to {@link LocalServices}.
*/
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 0544376959ee..b9969ceb6ec0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1106,6 +1106,21 @@ public final class DisplayPowerControllerTest {
verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true);
}
+ @Test
+ public void testPowerStateStopsOnDpcStop() {
+ // Set up
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1);
+
+ // Stop dpc
+ mHolder.dpc.stop();
+ advanceTime(1);
+
+ // Ensure dps has stopped
+ verify(mHolder.displayPowerState, times(1)).stop();
+ }
+
/**
* Creates a mock and registers it to {@link LocalServices}.
*/
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java
new file mode 100644
index 000000000000..167a412d3860
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.mockito.Mockito.times;
+
+import android.os.Handler;
+import android.os.test.TestLooper;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+
+@SmallTest
+public class DisplayPowerStateTest {
+ private static final int DISPLAY_ID = 123;
+
+ private DisplayPowerState mDisplayPowerState;
+ private TestLooper mTestLooper;
+ @Mock
+ private DisplayBlanker mDisplayBlankerMock;
+ @Mock
+ private ColorFade mColorFadeMock;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Before
+ public void setUp() {
+ mTestLooper = new TestLooper();
+ mDisplayPowerState = new DisplayPowerState(
+ mDisplayBlankerMock, mColorFadeMock, DISPLAY_ID, Display.STATE_ON,
+ new Handler(mTestLooper.getLooper()));
+ }
+
+ @Test
+ public void testColorFadeStopsOnDpsStop() {
+ mDisplayPowerState.stop();
+ verify(mColorFadeMock, times(1)).stop();
+ }
+}
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 0fe6e64b3b54..13c107d0a91e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -42,8 +42,12 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -55,6 +59,7 @@ import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.Process;
+import android.os.RemoteException;
import android.os.test.TestLooper;
import android.view.Display;
import android.view.DisplayAddress;
@@ -65,7 +70,7 @@ import androidx.test.filters.SmallTest;
import com.android.server.display.layout.DisplayIdProducer;
import com.android.server.display.layout.Layout;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
import org.junit.Before;
import org.junit.Test;
@@ -87,6 +92,7 @@ public class LogicalDisplayMapperTest {
private static int sUniqueTestDisplayId = 0;
private static final int DEVICE_STATE_CLOSED = 0;
private static final int DEVICE_STATE_OPEN = 2;
+ private static final int FLAG_GO_TO_SLEEP_ON_FOLD = 0;
private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1;
private static final File NON_EXISTING_FILE = new File("/non_existing_folder/should_not_exist");
@@ -101,7 +107,7 @@ public class LogicalDisplayMapperTest {
@Mock LogicalDisplayMapper.Listener mListenerMock;
@Mock Context mContextMock;
- @Mock FoldSettingWrapper mFoldSettingWrapperMock;
+ @Mock FoldSettingProvider mFoldSettingProviderMock;
@Mock Resources mResourcesMock;
@Mock IPowerManager mIPowerManagerMock;
@Mock IThermalService mIThermalServiceMock;
@@ -111,7 +117,7 @@ public class LogicalDisplayMapperTest {
@Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor;
@Before
- public void setUp() {
+ public void setUp() throws RemoteException {
// Share classloader to allow package private access.
System.setProperty("dexmaker.share_classloader", "true");
MockitoAnnotations.initMocks(this);
@@ -141,7 +147,9 @@ public class LogicalDisplayMapperTest {
when(mContextMock.getSystemServiceName(PowerManager.class))
.thenReturn(Context.POWER_SERVICE);
- when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(false);
+ when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(false);
+ when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false);
+ when(mIPowerManagerMock.isInteractive()).thenReturn(true);
when(mContextMock.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
when(mContextMock.getResources()).thenReturn(mResourcesMock);
when(mResourcesMock.getBoolean(
@@ -156,9 +164,10 @@ public class LogicalDisplayMapperTest {
mLooper = new TestLooper();
mHandler = new Handler(mLooper.getLooper());
- mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo,
+ mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mFoldSettingProviderMock,
+ mDisplayDeviceRepo,
mListenerMock, new DisplayManagerService.SyncRoot(), mHandler,
- mDeviceStateToLayoutMapSpy, mFoldSettingWrapperMock);
+ mDeviceStateToLayoutMapSpy);
}
@@ -574,8 +583,8 @@ public class LogicalDisplayMapperTest {
}
@Test
- public void testDeviceShouldNotSleepWhenFoldSettingTrue() {
- when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(true);
+ public void testDeviceShouldNotSleepWhenStayAwakeSettingTrue() {
+ when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(true);
assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
DEVICE_STATE_OPEN,
@@ -608,6 +617,26 @@ public class LogicalDisplayMapperTest {
}
@Test
+ public void testDeviceShouldPutToSleepWhenSleepSettingTrue() throws RemoteException {
+ when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(true);
+
+ finishBootAndFoldDevice();
+
+ verify(mIPowerManagerMock, atLeastOnce()).goToSleep(anyLong(), anyInt(),
+ eq(FLAG_GO_TO_SLEEP_ON_FOLD));
+ }
+
+ @Test
+ public void testDeviceShouldNotBePutToSleepWhenSleepSettingFalse() throws RemoteException {
+ when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false);
+
+ finishBootAndFoldDevice();
+
+ verify(mIPowerManagerMock, never()).goToSleep(anyLong(), anyInt(),
+ eq(FLAG_GO_TO_SLEEP_ON_FOLD));
+ }
+
+ @Test
public void testDeviceStateLocked() {
DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800,
FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
@@ -859,6 +888,15 @@ public class LogicalDisplayMapperTest {
// Helper Methods
/////////////////
+ private void finishBootAndFoldDevice() {
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_OPEN, false);
+ advanceTime(1000);
+ mLogicalDisplayMapper.onBootCompleted();
+ advanceTime(1000);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED, false);
+ advanceTime(1000);
+ }
+
private void createDefaultDisplay(Layout layout, DisplayDevice device) {
createDefaultDisplay(layout, info(device).address);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 9545a8a4544b..3d7ae349628e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -1862,6 +1862,13 @@ public class MockingOomAdjusterTests {
assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
assertBfsl(app2);
+
+ bindService(client2, app1, null, 0, mock(IBinder.class));
+ bindService(app1, client2, null, 0, mock(IBinder.class));
+ client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
+ updateOomAdj(app1, client1, client2);
+ assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
+ SCHED_GROUP_TOP_APP);
}
@SuppressWarnings("GuardedBy")
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java
new file mode 100644
index 000000000000..3514276ccb5b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.utils;
+
+import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_SLEEP_ON_FOLD;
+import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_STAY_AWAKE_ON_FOLD;
+
+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.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.R;
+import com.android.internal.util.SettingsWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class FoldSettingProviderTest {
+
+ private static final String SETTING_VALUE_INVALID = "invalid_fold_lock_behavior";
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private SettingsWrapper mSettingsWrapper;
+ private ContentResolver mContentResolver;
+ private FoldSettingProvider mFoldSettingProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContentResolver =
+ InstrumentationRegistry.getInstrumentation().getContext().getContentResolver();
+ when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mContext.getResources()).thenReturn(mResources);
+ setFoldLockBehaviorAvailability(true);
+
+ mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+ }
+
+ @Test
+ public void foldSettingNotAvailable_returnDefaultSetting() {
+ setFoldLockBehaviorAvailability(false);
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+ mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+ boolean shouldSelectiveStayAwakeOnFold =
+ mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+ assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+ }
+
+ @Test
+ public void foldSettingNotAvailable_notReturnStayAwakeOnFoldTrue() {
+ setFoldLockBehaviorAvailability(false);
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+ mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+ boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold();
+
+ assertThat(shouldStayAwakeOnFold).isFalse();
+ }
+
+ @Test
+ public void foldSettingNotAvailable_notReturnSleepOnFoldTrue() {
+ setFoldLockBehaviorAvailability(false);
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_SLEEP_ON_FOLD);
+ mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+ boolean shouldSleepOnFold = mFoldSettingProvider.shouldSleepOnFold();
+
+ assertThat(shouldSleepOnFold).isFalse();
+ }
+
+ @Test
+ public void foldSettingAvailable_returnCorrectFoldSetting() {
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+
+ boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold();
+
+ assertThat(shouldStayAwakeOnFold).isTrue();
+ }
+
+ @Test
+ public void foldSettingInvalid_returnDefaultSetting() {
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_INVALID);
+
+ boolean shouldSelectiveStayAwakeOnFold =
+ mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+ assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+ }
+
+ @Test
+ public void foldSettingNotDefined_returnDefaultSetting() {
+ setFoldLockBehaviorSettingValue(null);
+
+ boolean shouldSelectiveStayAwakeOnFold =
+ mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+ assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+ }
+
+ private void setFoldLockBehaviorAvailability(boolean isFoldLockBehaviorEnabled) {
+ when(mResources.getBoolean(R.bool.config_fold_lock_behavior)).thenReturn(
+ isFoldLockBehaviorEnabled);
+ }
+
+ private void setFoldLockBehaviorSettingValue(String foldLockBehaviorSettingValue) {
+ when(mSettingsWrapper.getStringForUser(any(),
+ eq(Settings.System.FOLD_LOCK_BEHAVIOR),
+ eq(UserHandle.USER_CURRENT))).thenReturn(foldLockBehaviorSettingValue);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
index 0b730f139f3e..fa6e7f60c1b0 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
@@ -115,6 +115,11 @@ public class AuthenticationStatsCollectorTest {
// Assert that the user doesn't exist in the map initially.
assertThat(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1)).isNull();
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
mAuthenticationStatsCollector.authenticate(USER_ID_1, true /* authenticated */);
AuthenticationStats authenticationStats =
@@ -130,6 +135,11 @@ public class AuthenticationStatsCollectorTest {
// Assert that the user doesn't exist in the map initially.
assertThat(mAuthenticationStatsCollector.getAuthenticationStatsForUser(USER_ID_1)).isNull();
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
AuthenticationStats authenticationStats =
@@ -176,6 +186,11 @@ public class AuthenticationStatsCollectorTest {
40 /* rejectedAttempts */, 0 /* enrollmentNotifications */,
0 /* modality */));
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
// Assert that no notification should be sent.
@@ -233,13 +248,13 @@ public class AuthenticationStatsCollectorTest {
// Assert that no notification should be sent.
verify(mBiometricNotification, never()).sendFaceEnrollNotification(any());
verify(mBiometricNotification, never()).sendFpEnrollNotification(any());
- // Assert that data has been reset.
+ // Assert that data hasn't been reset.
AuthenticationStats authenticationStats = mAuthenticationStatsCollector
.getAuthenticationStatsForUser(USER_ID_1);
- assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
- assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(500);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(400);
assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0);
- assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(0.8f);
}
@Test
@@ -260,13 +275,13 @@ public class AuthenticationStatsCollectorTest {
// Assert that no notification should be sent.
verify(mBiometricNotification, never()).sendFaceEnrollNotification(any());
verify(mBiometricNotification, never()).sendFpEnrollNotification(any());
- // Assert that data has been reset.
+ // Assert that data hasn't been reset.
AuthenticationStats authenticationStats = mAuthenticationStatsCollector
.getAuthenticationStatsForUser(USER_ID_1);
- assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
- assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+ assertThat(authenticationStats.getTotalAttempts()).isEqualTo(500);
+ assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(400);
assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0);
- assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+ assertThat(authenticationStats.getFrr()).isWithin(0f).of(0.8f);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
index 20d5f93a2c07..78d3a9dd9f9e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
@@ -147,6 +148,24 @@ public class FingerprintDetectClientTest {
verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
}
+ @Test
+ public void testWhenListenerIsNull() {
+ final AidlSession aidl = new AidlSession(0, mHal, USER_ID, mHalSessionCallback);
+ final FingerprintDetectClient client = new FingerprintDetectClient(mContext, () -> aidl,
+ mToken, 6 /* requestId */, null /* listener */,
+ new FingerprintAuthenticateOptions.Builder()
+ .setUserId(2)
+ .setSensorId(1)
+ .setOpPackageName("a-test")
+ .build(),
+ mBiometricLogger, mBiometricContext,
+ mUdfpsOverlayController, true /* isStrongBiometric */);
+ client.start(mCallback);
+ client.onInteractionDetected();
+
+ verify(mCallback).onClientFinished(eq(client), anyBoolean());
+ }
+
private FingerprintDetectClient createClient() throws RemoteException {
return createClient(200 /* version */);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index 2273fcd22b38..9f75cf8d552e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -113,6 +113,42 @@ public class UserManagerServiceUserInfoTest {
assertUserInfoEquals(data.info, read.info, /* parcelCopy= */ false);
}
+ /** Tests that device policy restrictions are written/read properly. */
+ @Test
+ public void testWriteReadDevicePolicyUserRestrictions() throws Exception {
+ final String globalRestriction = UserManager.DISALLOW_FACTORY_RESET;
+ final String localRestriction = UserManager.DISALLOW_CONFIG_DATE_TIME;
+
+ UserData data = new UserData();
+ data.info = createUser(100, FLAG_FULL, "A type");
+
+ mUserManagerService.putUserInfo(data.info);
+
+ // Set a global and user restriction so they get written out to the user file.
+ setUserRestrictions(data.info.id, globalRestriction, localRestriction, true);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(baos);
+ mUserManagerService.writeUserLP(data, out);
+ byte[] bytes = baos.toByteArray();
+
+ // Clear the restrictions to see if they are properly read in from the user file.
+ setUserRestrictions(data.info.id, globalRestriction, localRestriction, false);
+
+ mUserManagerService.readUserLP(data.info.id, new ByteArrayInputStream(bytes));
+ assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(globalRestriction));
+ assertTrue(mUserManagerService.hasUserRestrictionOnAnyUser(localRestriction));
+ }
+
+ /** Sets a global and local restriction and verifies they were set properly **/
+ private void setUserRestrictions(int id, String global, String local, boolean enabled) {
+ mUserManagerService.setUserRestrictionInner(UserHandle.USER_ALL, global, enabled);
+ assertEquals(mUserManagerService.hasUserRestrictionOnAnyUser(global), enabled);
+
+ mUserManagerService.setUserRestrictionInner(id, local, enabled);
+ assertEquals(mUserManagerService.hasUserRestrictionOnAnyUser(local), enabled);
+ }
+
@Test
public void testParcelUnparcelUserInfo() throws Exception {
UserInfo info = createUser();
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java b/services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java
index 93464cdd13d0..d9bc74dfb1cb 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/FakeServiceConfigAccessor.java
@@ -35,7 +35,7 @@ public class FakeServiceConfigAccessor implements ServiceConfigAccessor {
private final List<StateChangeListener> mConfigurationInternalChangeListeners =
new ArrayList<>();
- private ConfigurationInternal mConfigurationInternal;
+ private ConfigurationInternal mCurrentUserConfigurationInternal;
@Override
public void addConfigurationInternalChangeListener(StateChangeListener listener) {
@@ -49,21 +49,23 @@ public class FakeServiceConfigAccessor implements ServiceConfigAccessor {
@Override
public ConfigurationInternal getCurrentUserConfigurationInternal() {
- return mConfigurationInternal;
+ return mCurrentUserConfigurationInternal;
}
@Override
public boolean updateConfiguration(
- @UserIdInt int userID, @NonNull TimeConfiguration requestedChanges,
+ @UserIdInt int userId, @NonNull TimeConfiguration requestedChanges,
boolean bypassUserPolicyChecks) {
- assertNotNull(mConfigurationInternal);
+ assertNotNull(mCurrentUserConfigurationInternal);
assertNotNull(requestedChanges);
+ ConfigurationInternal toUpdate = getConfigurationInternal(userId);
+
// Simulate the real strategy's behavior: the new configuration will be updated to be the
// old configuration merged with the new if the user has the capability to up the settings.
// Then, if the configuration changed, the change listener is invoked.
TimeCapabilitiesAndConfig capabilitiesAndConfig =
- mConfigurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks);
+ toUpdate.createCapabilitiesAndConfig(bypassUserPolicyChecks);
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
TimeConfiguration configuration = capabilitiesAndConfig.getConfiguration();
TimeConfiguration newConfiguration =
@@ -73,28 +75,36 @@ public class FakeServiceConfigAccessor implements ServiceConfigAccessor {
}
if (!newConfiguration.equals(capabilitiesAndConfig.getConfiguration())) {
- mConfigurationInternal = mConfigurationInternal.merge(newConfiguration);
+ mCurrentUserConfigurationInternal = toUpdate.merge(newConfiguration);
// Note: Unlike the real strategy, the listeners are invoked synchronously.
- simulateConfigurationChangeForTests();
+ notifyConfigurationChange();
}
return true;
}
- void initializeConfiguration(ConfigurationInternal configurationInternal) {
- mConfigurationInternal = configurationInternal;
+
+ void initializeCurrentUserConfiguration(ConfigurationInternal configurationInternal) {
+ mCurrentUserConfigurationInternal = configurationInternal;
}
- void simulateConfigurationChangeForTests() {
- for (StateChangeListener listener : mConfigurationInternalChangeListeners) {
- listener.onChange();
- }
+ void simulateCurrentUserConfigurationInternalChange(
+ ConfigurationInternal configurationInternal) {
+ mCurrentUserConfigurationInternal = configurationInternal;
+ // Note: Unlike the real strategy, the listeners are invoked synchronously.
+ notifyConfigurationChange();
}
@Override
public ConfigurationInternal getConfigurationInternal(int userId) {
assertEquals("Multi-user testing not supported currently",
- userId, mConfigurationInternal.getUserId());
- return mConfigurationInternal;
+ userId, mCurrentUserConfigurationInternal.getUserId());
+ return mCurrentUserConfigurationInternal;
+ }
+
+ private void notifyConfigurationChange() {
+ for (StateChangeListener listener : mConfigurationInternalChangeListeners) {
+ listener.onChange();
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
index 87aa2725491b..a7a9c0cd86f2 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
@@ -18,6 +18,8 @@ package com.android.server.timedetector;
import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
+import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
import android.app.time.TimeState;
import android.app.time.UnixEpochTime;
import android.app.timedetector.ManualTimeSuggestion;
@@ -31,10 +33,20 @@ import com.android.server.timezonedetector.StateChangeListener;
* in tests.
*/
public class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
+ private final FakeServiceConfigAccessor mFakeServiceConfigAccessor;
+
// State
private TimeState mTimeState;
private NetworkTimeSuggestion mLatestNetworkTimeSuggestion;
+ FakeTimeDetectorStrategy() {
+ mFakeServiceConfigAccessor = new FakeServiceConfigAccessor();
+ }
+
+ void initializeConfiguration(ConfigurationInternal configuration) {
+ mFakeServiceConfigAccessor.initializeCurrentUserConfiguration(configuration);
+ }
+
@Override
public TimeState getTimeState() {
return mTimeState;
@@ -51,6 +63,26 @@ public class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
}
@Override
+ public void addChangeListener(StateChangeListener listener) {
+ mFakeServiceConfigAccessor.addConfigurationInternalChangeListener(listener);
+ }
+
+ @Override
+ public TimeCapabilitiesAndConfig getCapabilitiesAndConfig(int userId,
+ boolean bypassUserPolicyChecks) {
+ ConfigurationInternal configurationInternal =
+ mFakeServiceConfigAccessor.getConfigurationInternal(userId);
+ return configurationInternal.createCapabilitiesAndConfig(bypassUserPolicyChecks);
+ }
+
+ @Override
+ public boolean updateConfiguration(int userId, TimeConfiguration configuration,
+ boolean bypassUserPolicyChecks) {
+ return mFakeServiceConfigAccessor.updateConfiguration(
+ userId, configuration, bypassUserPolicyChecks);
+ }
+
+ @Override
public void suggestTelephonyTime(TelephonyTimeSuggestion suggestion) {
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
index a0845a64757e..de5a37b43df8 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorInternalImplTest.java
@@ -89,7 +89,7 @@ public class TimeDetectorInternalImplTest {
public void testGetCapabilitiesAndConfigForDpm() throws Exception {
final boolean autoDetectionEnabled = true;
ConfigurationInternal testConfig = createConfigurationInternal(autoDetectionEnabled);
- mFakeServiceConfigAccessorSpy.initializeConfiguration(testConfig);
+ mFakeServiceConfigAccessorSpy.initializeCurrentUserConfiguration(testConfig);
TimeCapabilitiesAndConfig actualCapabilitiesAndConfig =
mTimeDetectorInternal.getCapabilitiesAndConfigForDpm();
@@ -108,7 +108,8 @@ public class TimeDetectorInternalImplTest {
final boolean autoDetectionEnabled = false;
ConfigurationInternal initialConfigurationInternal =
createConfigurationInternal(autoDetectionEnabled);
- mFakeServiceConfigAccessorSpy.initializeConfiguration(initialConfigurationInternal);
+ mFakeServiceConfigAccessorSpy.initializeCurrentUserConfiguration(
+ initialConfigurationInternal);
TimeConfiguration timeConfiguration = new TimeConfiguration.Builder()
.setAutoDetectionEnabled(true)
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index daa682342836..6b2d4b01dd08 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -83,7 +83,6 @@ public class TimeDetectorServiceTest {
private HandlerThread mHandlerThread;
private TestHandler mTestHandler;
private TestCallerIdentityInjector mTestCallerIdentityInjector;
- private FakeServiceConfigAccessor mFakeServiceConfigAccessorSpy;
private FakeTimeDetectorStrategy mFakeTimeDetectorStrategySpy;
private NtpTrustedTime mMockNtpTrustedTime;
@@ -101,13 +100,12 @@ public class TimeDetectorServiceTest {
mTestCallerIdentityInjector = new TestCallerIdentityInjector();
mTestCallerIdentityInjector.initializeCallingUserId(ARBITRARY_USER_ID);
- mFakeServiceConfigAccessorSpy = spy(new FakeServiceConfigAccessor());
mFakeTimeDetectorStrategySpy = spy(new FakeTimeDetectorStrategy());
mMockNtpTrustedTime = mock(NtpTrustedTime.class);
mTimeDetectorService = new TimeDetectorService(
mMockContext, mTestHandler, mTestCallerIdentityInjector,
- mFakeServiceConfigAccessorSpy, mFakeTimeDetectorStrategySpy, mMockNtpTrustedTime);
+ mFakeTimeDetectorStrategySpy, mMockNtpTrustedTime);
}
@After
@@ -132,14 +130,14 @@ public class TimeDetectorServiceTest {
ConfigurationInternal configuration =
createConfigurationInternal(true /* autoDetectionEnabled*/);
- mFakeServiceConfigAccessorSpy.initializeConfiguration(configuration);
+ mFakeTimeDetectorStrategySpy.initializeConfiguration(configuration);
TimeCapabilitiesAndConfig actualCapabilitiesAndConfig =
mTimeDetectorService.getCapabilitiesAndConfig();
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION), anyString());
int expectedUserId = mTestCallerIdentityInjector.getCallingUserId();
- verify(mFakeServiceConfigAccessorSpy).getConfigurationInternal(expectedUserId);
+ verify(mFakeTimeDetectorStrategySpy).getCapabilitiesAndConfig(expectedUserId, false);
boolean bypassUserPolicyChecks = false;
TimeCapabilitiesAndConfig expectedCapabilitiesAndConfig =
@@ -174,7 +172,7 @@ public class TimeDetectorServiceTest {
public void testListenerRegistrationAndCallbacks() throws Exception {
ConfigurationInternal initialConfiguration =
createConfigurationInternal(false /* autoDetectionEnabled */);
- mFakeServiceConfigAccessorSpy.initializeConfiguration(initialConfiguration);
+ mFakeTimeDetectorStrategySpy.initializeConfiguration(initialConfiguration);
IBinder mockListenerBinder = mock(IBinder.class);
ITimeDetectorListener mockListener = mock(ITimeDetectorListener.class);
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 4df21e00d61c..dd58135a8e87 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -29,14 +29,22 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
+import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
import android.app.time.TimeState;
import android.app.time.UnixEpochTime;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.TimestampedValue;
+import android.util.IndentingPrintWriter;
import com.android.server.SystemClockTime.TimeConfidence;
import com.android.server.timedetector.TimeDetectorStrategy.Origin;
@@ -47,14 +55,12 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.PrintWriter;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
@@ -120,13 +126,108 @@ public class TimeDetectorStrategyImplTest {
.build();
private FakeEnvironment mFakeEnvironment;
+ private FakeServiceConfigAccessor mFakeServiceConfigAccessorSpy;
+ private TimeDetectorStrategyImpl mTimeDetectorStrategy;
@Before
public void setUp() {
mFakeEnvironment = new FakeEnvironment();
- mFakeEnvironment.initializeConfig(CONFIG_AUTO_DISABLED);
mFakeEnvironment.initializeFakeClocks(
ARBITRARY_CLOCK_INITIALIZATION_INFO, TIME_CONFIDENCE_LOW);
+
+ mFakeServiceConfigAccessorSpy = spy(new FakeServiceConfigAccessor());
+ mFakeServiceConfigAccessorSpy.initializeCurrentUserConfiguration(CONFIG_AUTO_DISABLED);
+
+ mTimeDetectorStrategy = new TimeDetectorStrategyImpl(
+ mFakeEnvironment, mFakeServiceConfigAccessorSpy);
+ }
+
+ @Test
+ public void testChangeListenerBehavior() throws Exception {
+ TestStateChangeListener stateChangeListener = new TestStateChangeListener();
+ mTimeDetectorStrategy.addChangeListener(stateChangeListener);
+
+ boolean bypassUserPolicyChecks = false;
+
+ // Report a config change, but not one that actually changes anything.
+ {
+ mFakeServiceConfigAccessorSpy.simulateCurrentUserConfigurationInternalChange(
+ CONFIG_AUTO_DISABLED);
+ assertStateChangeNotificationsSent(stateChangeListener, 0);
+ assertEquals(CONFIG_AUTO_DISABLED,
+ mTimeDetectorStrategy.getCachedCapabilitiesAndConfigForTests());
+ }
+
+ // Report a config change that actually changes something.
+ {
+ mFakeServiceConfigAccessorSpy.simulateCurrentUserConfigurationInternalChange(
+ CONFIG_AUTO_ENABLED);
+ assertStateChangeNotificationsSent(stateChangeListener, 1);
+ assertEquals(CONFIG_AUTO_ENABLED,
+ mTimeDetectorStrategy.getCachedCapabilitiesAndConfigForTests());
+ }
+
+ // Perform a (current user) update via the strategy.
+ {
+ TimeConfiguration requestedChanges =
+ new TimeConfiguration.Builder().setAutoDetectionEnabled(false).build();
+ mTimeDetectorStrategy.updateConfiguration(
+ ARBITRARY_USER_ID, requestedChanges, bypassUserPolicyChecks);
+ assertStateChangeNotificationsSent(stateChangeListener, 1);
+ }
+ }
+
+ // Current user behavior: the strategy caches and returns the latest configuration.
+ @Test
+ public void testReadAndWriteConfiguration() throws Exception {
+ ConfigurationInternal currentUserConfig = CONFIG_AUTO_ENABLED;
+ mFakeServiceConfigAccessorSpy.simulateCurrentUserConfigurationInternalChange(
+ currentUserConfig);
+
+ final boolean bypassUserPolicyChecks = false;
+
+ ConfigurationInternal cachedConfigurationInternal =
+ mTimeDetectorStrategy.getCachedCapabilitiesAndConfigForTests();
+ assertEquals(currentUserConfig, cachedConfigurationInternal);
+
+ // Confirm getCapabilitiesAndConfig() does not call through to the ServiceConfigAccessor.
+ {
+ reset(mFakeServiceConfigAccessorSpy);
+ TimeCapabilitiesAndConfig actualCapabilitiesAndConfig =
+ mTimeDetectorStrategy.getCapabilitiesAndConfig(
+ currentUserConfig.getUserId(), bypassUserPolicyChecks);
+ verify(mFakeServiceConfigAccessorSpy, never()).getConfigurationInternal(
+ currentUserConfig.getUserId());
+
+ TimeCapabilitiesAndConfig expectedCapabilitiesAndConfig =
+ currentUserConfig.createCapabilitiesAndConfig(bypassUserPolicyChecks);
+ assertEquals(expectedCapabilitiesAndConfig.getCapabilities(),
+ actualCapabilitiesAndConfig.getCapabilities());
+ assertEquals(expectedCapabilitiesAndConfig.getConfiguration(),
+ actualCapabilitiesAndConfig.getConfiguration());
+ }
+
+ // Confirm updateConfiguration() calls through to the ServiceConfigAccessor and updates
+ // the cached copy.
+ {
+ boolean newAutoDetectionEnabled =
+ !cachedConfigurationInternal.getAutoDetectionEnabledBehavior();
+ TimeConfiguration requestedChanges = new TimeConfiguration.Builder()
+ .setAutoDetectionEnabled(newAutoDetectionEnabled)
+ .build();
+ ConfigurationInternal expectedConfigAfterChange =
+ new ConfigurationInternal.Builder(cachedConfigurationInternal)
+ .setAutoDetectionEnabledSetting(newAutoDetectionEnabled)
+ .build();
+
+ reset(mFakeServiceConfigAccessorSpy);
+ mTimeDetectorStrategy.updateConfiguration(
+ currentUserConfig.getUserId(), requestedChanges, bypassUserPolicyChecks);
+ verify(mFakeServiceConfigAccessorSpy, times(1)).updateConfiguration(
+ currentUserConfig.getUserId(), requestedChanges, bypassUserPolicyChecks);
+ assertEquals(expectedConfigAfterChange,
+ mTimeDetectorStrategy.getCachedCapabilitiesAndConfigForTests());
+ }
}
@Test
@@ -1939,20 +2040,14 @@ public class TimeDetectorStrategyImplTest {
private final List<Runnable> mAsyncRunnables = new ArrayList<>();
- private ConfigurationInternal mConfigurationInternal;
private boolean mWakeLockAcquired;
private long mElapsedRealtimeMillis;
private long mSystemClockMillis;
private int mSystemClockConfidence = TIME_CONFIDENCE_LOW;
- private StateChangeListener mConfigurationInternalChangeListener;
// Tracking operations.
private boolean mSystemClockWasSet;
- void initializeConfig(ConfigurationInternal configurationInternal) {
- mConfigurationInternal = configurationInternal;
- }
-
public void initializeFakeClocks(
TimestampedValue<Instant> timeInfo, @TimeConfidence int timeConfidence) {
pokeElapsedRealtimeMillis(timeInfo.getReferenceTimeMillis());
@@ -1960,16 +2055,6 @@ public class TimeDetectorStrategyImplTest {
}
@Override
- public void setConfigurationInternalChangeListener(StateChangeListener listener) {
- mConfigurationInternalChangeListener = Objects.requireNonNull(listener);
- }
-
- @Override
- public ConfigurationInternal getCurrentUserConfigurationInternal() {
- return mConfigurationInternal;
- }
-
- @Override
public void acquireWakeLock() {
if (mWakeLockAcquired) {
fail("Wake lock already acquired");
@@ -2019,7 +2104,7 @@ public class TimeDetectorStrategyImplTest {
}
@Override
- public void dumpDebugLog(PrintWriter printWriter) {
+ public void dumpDebugLog(IndentingPrintWriter pw) {
// No-op for tests
}
@@ -2037,11 +2122,6 @@ public class TimeDetectorStrategyImplTest {
mAsyncRunnables.clear();
}
- void simulateConfigurationInternalChange(ConfigurationInternal configurationInternal) {
- mConfigurationInternal = configurationInternal;
- mConfigurationInternalChangeListener.onChange();
- }
-
void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) {
mElapsedRealtimeMillis = elapsedRealtimeMillis;
}
@@ -2095,13 +2175,6 @@ public class TimeDetectorStrategyImplTest {
*/
private class Script {
- private final TimeDetectorStrategyImpl mTimeDetectorStrategy;
-
- Script() {
- mFakeEnvironment = new FakeEnvironment();
- mTimeDetectorStrategy = new TimeDetectorStrategyImpl(mFakeEnvironment);
- }
-
Script pokeFakeClocks(TimestampedValue<Instant> initialClockTime,
@TimeConfidence int timeConfidence) {
mFakeEnvironment.pokeElapsedRealtimeMillis(initialClockTime.getReferenceTimeMillis());
@@ -2122,7 +2195,8 @@ public class TimeDetectorStrategyImplTest {
* Simulates the user / user's configuration changing.
*/
Script simulateConfigurationInternalChange(ConfigurationInternal configurationInternal) {
- mFakeEnvironment.simulateConfigurationInternalChange(configurationInternal);
+ mFakeServiceConfigAccessorSpy.simulateCurrentUserConfigurationInternalChange(
+ configurationInternal);
return this;
}
@@ -2167,14 +2241,15 @@ public class TimeDetectorStrategyImplTest {
Script simulateAutoTimeDetectionToggle() {
ConfigurationInternal configurationInternal =
- mFakeEnvironment.getCurrentUserConfigurationInternal();
+ mFakeServiceConfigAccessorSpy.getCurrentUserConfigurationInternal();
boolean autoDetectionEnabledSetting =
!configurationInternal.getAutoDetectionEnabledSetting();
ConfigurationInternal newConfigurationInternal =
new ConfigurationInternal.Builder(configurationInternal)
.setAutoDetectionEnabledSetting(autoDetectionEnabledSetting)
.build();
- mFakeEnvironment.simulateConfigurationInternalChange(newConfigurationInternal);
+ mFakeServiceConfigAccessorSpy.simulateCurrentUserConfigurationInternalChange(
+ newConfigurationInternal);
return this;
}
@@ -2389,4 +2464,12 @@ public class TimeDetectorStrategyImplTest {
return LocalDateTime.of(year, monthInYear, day, hourOfDay, minute, second)
.toInstant(ZoneOffset.UTC);
}
+
+ private void assertStateChangeNotificationsSent(
+ TestStateChangeListener stateChangeListener, int expectedCount) {
+ // The fake environment needs to be told to run posted work.
+ mFakeEnvironment.runAsyncRunnables();
+
+ stateChangeListener.assertNotificationsReceivedAndReset(expectedCount);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index f158ce14549f..9d2b34cc6ba5 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -84,6 +84,7 @@ import android.view.Display;
import android.view.InputDevice;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.FrameworkStatsLog;
@@ -813,6 +814,7 @@ public class VibratorManagerServiceTest {
eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString());
}
+ @FlakyTest
@Test
public void vibrate_withOngoingRepeatingVibration_ignoresEffect() throws Exception {
mockVibrators(1);
@@ -899,6 +901,7 @@ public class VibratorManagerServiceTest {
cancelVibrate(service); // Clean up repeating effect.
}
+ @FlakyTest
@Test
public void vibrate_withNewSameImportanceVibrationButOngoingIsRepeating_ignoreNewVibration()
throws Exception {
@@ -952,6 +955,7 @@ public class VibratorManagerServiceTest {
cancelVibrate(service); // Clean up repeating effect.
}
+ @FlakyTest
@Test
public void vibrate_withNewUnknownUsageVibrationAndNotRepeating_ignoreNewVibration()
throws Exception {
@@ -1687,6 +1691,7 @@ public class VibratorManagerServiceTest {
cancelVibrate(service); // Clean up long effect.
}
+ @FlakyTest
@Test
public void onExternalVibration_withNewSameImportanceButRepeating_cancelsOngoingVibration()
throws Exception {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index bbec091b9924..b8f6cb8b5eba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -16,6 +16,11 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -76,6 +81,7 @@ import java.util.concurrent.CountDownLatch;
@RunWith(WindowTestRunner.class)
public class ContentRecorderTests extends WindowTestsBase {
private static IBinder sTaskWindowContainerToken;
+ private DisplayContent mVirtualDisplayContent;
private Task mTask;
private final ContentRecordingSession mDisplaySession =
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
@@ -106,11 +112,11 @@ public class ContentRecorderTests extends WindowTestsBase {
displayInfo.logicalWidth = sSurfaceSize.x;
displayInfo.logicalHeight = sSurfaceSize.y;
displayInfo.state = STATE_ON;
- final DisplayContent virtualDisplayContent = createNewDisplay(displayInfo);
- final int displayId = virtualDisplayContent.getDisplayId();
- mContentRecorder = new ContentRecorder(virtualDisplayContent,
+ mVirtualDisplayContent = createNewDisplay(displayInfo);
+ final int displayId = mVirtualDisplayContent.getDisplayId();
+ mContentRecorder = new ContentRecorder(mVirtualDisplayContent,
mMediaProjectionManagerWrapper);
- spyOn(virtualDisplayContent);
+ spyOn(mVirtualDisplayContent);
// GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
// record.
@@ -118,7 +124,7 @@ public class ContentRecorderTests extends WindowTestsBase {
mDisplaySession.setDisplayToRecord(mDefaultDisplay.mDisplayId);
// GIVEN there is a window token associated with a task to record.
- sTaskWindowContainerToken = setUpTaskWindowContainerToken(virtualDisplayContent);
+ sTaskWindowContainerToken = setUpTaskWindowContainerToken(mVirtualDisplayContent);
mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
mTaskSession.setVirtualDisplayId(displayId);
@@ -251,7 +257,11 @@ public class ContentRecorderTests extends WindowTestsBase {
public void testOnConfigurationChanged_resizesSurface() {
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
- mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
+ // Ensure a different orientation when we check if something has changed.
+ @Configuration.Orientation final int lastOrientation =
+ mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ mContentRecorder.onConfigurationChanged(lastOrientation);
verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
anyFloat());
@@ -260,12 +270,53 @@ public class ContentRecorderTests extends WindowTestsBase {
}
@Test
+ public void testOnConfigurationChanged_resizesVirtualDisplay() {
+ final int newWidth = 55;
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+
+ // The user rotates the device, so the host app resizes the virtual display for the capture.
+ resizeDisplay(mDisplayContent, newWidth, sSurfaceSize.y);
+ resizeDisplay(mVirtualDisplayContent, newWidth, sSurfaceSize.y);
+ mContentRecorder.onConfigurationChanged(mDisplayContent.getConfiguration().orientation);
+
+ verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
+ anyFloat());
+ verify(mTransaction, atLeast(2)).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
+ anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testOnConfigurationChanged_rotateVirtualDisplay() {
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+
+ // Change a value that we shouldn't rely upon; it has the wrong type.
+ mVirtualDisplayContent.setOverrideOrientation(SCREEN_ORIENTATION_FULL_SENSOR);
+ mContentRecorder.onConfigurationChanged(
+ mVirtualDisplayContent.getConfiguration().orientation);
+
+ // No resize is issued, only the initial transformations when we started recording.
+ verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(),
+ anyFloat());
+ verify(mTransaction).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
+ anyFloat(), anyFloat());
+ }
+
+ @Test
public void testOnTaskOrientationConfigurationChanged_resizesSurface() {
mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
Configuration config = mTask.getConfiguration();
- config.orientation = ORIENTATION_PORTRAIT;
+ // Ensure a different orientation when we compare.
+ @Configuration.Orientation final int orientation =
+ config.orientation == ORIENTATION_PORTRAIT ? ORIENTATION_LANDSCAPE
+ : ORIENTATION_PORTRAIT;
+ final Rect lastBounds = config.windowConfiguration.getBounds();
+ config.orientation = orientation;
+ config.windowConfiguration.setBounds(
+ new Rect(0, 0, lastBounds.height(), lastBounds.width()));
mTask.onConfigurationChanged(config);
verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
@@ -278,13 +329,15 @@ public class ContentRecorderTests extends WindowTestsBase {
public void testOnTaskBoundsConfigurationChanged_notifiesCallback() {
mTask.getRootTask().setWindowingMode(WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
+ final int minWidth = 222;
+ final int minHeight = 777;
final int recordedWidth = 333;
final int recordedHeight = 999;
final ActivityInfo info = new ActivityInfo();
info.windowLayout = new ActivityInfo.WindowLayout(-1 /* width */,
-1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */,
- Gravity.NO_GRAVITY, recordedWidth, recordedHeight);
+ Gravity.NO_GRAVITY, minWidth, minHeight);
mTask.setMinDimensions(info);
// WHEN a recording is ongoing.
@@ -310,6 +363,39 @@ public class ContentRecorderTests extends WindowTestsBase {
}
@Test
+ public void testTaskWindowingModeChanged_pip_stopsRecording() {
+ // WHEN a recording is ongoing.
+ mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+ // WHEN a configuration change arrives, and the task is now pinned.
+ mTask.setWindowingMode(WINDOWING_MODE_PINNED);
+ Configuration configuration = mTask.getConfiguration();
+ mTask.onConfigurationChanged(configuration);
+
+ // THEN recording is paused.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
+
+ @Test
+ public void testTaskWindowingModeChanged_fullscreen_startsRecording() {
+ // WHEN a recording is ongoing.
+ mTask.setWindowingMode(WINDOWING_MODE_PINNED);
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+
+ // WHEN the task is now fullscreen.
+ mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mContentRecorder.updateRecording();
+
+ // THEN recording is started.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+ }
+
+ @Test
public void testStartRecording_notifiesCallback_taskSession() {
// WHEN a recording is ongoing.
mContentRecorder.setContentRecordingSession(mTaskSession);
@@ -334,6 +420,45 @@ public class ContentRecorderTests extends WindowTestsBase {
}
@Test
+ public void testStartRecording_taskInPIP_recordingNotStarted() {
+ // GIVEN a task is in PIP.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mTask.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ // WHEN a recording tries to start.
+ mContentRecorder.updateRecording();
+
+ // THEN recording does not start.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
+
+ @Test
+ public void testStartRecording_taskInSplit_recordingStarted() {
+ // GIVEN a task is in PIP.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+
+ // WHEN a recording tries to start.
+ mContentRecorder.updateRecording();
+
+ // THEN recording does not start.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+ }
+
+ @Test
+ public void testStartRecording_taskInFullscreen_recordingStarted() {
+ // GIVEN a task is in PIP.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ // WHEN a recording tries to start.
+ mContentRecorder.updateRecording();
+
+ // THEN recording does not start.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+ }
+
+ @Test
public void testOnVisibleRequestedChanged_notifiesCallback() {
// WHEN a recording is ongoing.
mContentRecorder.setContentRecordingSession(mTaskSession);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index dd90e0450280..bf86563e3d86 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR;
import static android.view.DisplayCutout.NO_CUTOUT;
import static android.view.InsetsSource.ID_IME;
import static android.view.RoundedCorners.NO_ROUNDED_CORNERS;
@@ -427,11 +428,11 @@ public class DisplayPolicyTests extends WindowTestsBase {
@SetupWindows(addWindows = { W_NAVIGATION_BAR, W_INPUT_METHOD })
@Test
public void testImeMinimalSourceFrame() {
+ Assume.assumeFalse("Behavior no longer needed with ENABLE_HIDE_IME_CAPTION_BAR",
+ ENABLE_HIDE_IME_CAPTION_BAR);
+
final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
- final DisplayInfo displayInfo = new DisplayInfo();
- displayInfo.logicalWidth = 1000;
- displayInfo.logicalHeight = 2000;
- displayInfo.rotation = ROTATION_0;
+ final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
WindowManager.LayoutParams attrs = mNavBarWindow.mAttrs;
displayPolicy.addWindowLw(mNavBarWindow, attrs);
@@ -466,10 +467,6 @@ public class DisplayPolicyTests extends WindowTestsBase {
@Test
public void testImeInsetsGivenContentFrame() {
final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
- final DisplayInfo displayInfo = new DisplayInfo();
- displayInfo.logicalWidth = 1000;
- displayInfo.logicalHeight = 2000;
- displayInfo.rotation = ROTATION_0;
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
mImeWindow.getControllableInsetProvider().setServerVisible(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 994dcf1e2ea5..ffa1ed926766 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -23,8 +23,6 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
@@ -108,7 +106,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
@Test
public void testControlsForDispatch_forceStatusBarVisible() {
- addStatusBar().mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
+ addStatusBar().mAttrs.forciblyShownTypes |= statusBars();
addNavigationBar();
final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
@@ -120,8 +118,8 @@ public class InsetsPolicyTest extends WindowTestsBase {
@Test
public void testControlsForDispatch_statusBarForceShowNavigation() {
- addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade").mAttrs.privateFlags |=
- PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade").mAttrs.forciblyShownTypes |=
+ navigationBars();
addStatusBar();
addNavigationBar();
@@ -135,7 +133,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
@Test
public void testControlsForDispatch_statusBarForceShowNavigation_butFocusedAnyways() {
WindowState notifShade = addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade");
- notifShade.mAttrs.privateFlags |= PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ notifShade.mAttrs.forciblyShownTypes |= navigationBars();
addNavigationBar();
mDisplayContent.getInsetsPolicy().updateBarControlTarget(notifShade);
@@ -329,6 +327,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
addNavigationBar().getControllableInsetProvider().getSource();
statusBarSource.setVisible(false);
navBarSource.setVisible(false);
+ mAppWindow.setRequestedVisibleTypes(0, navigationBars() | statusBars());
mAppWindow.mAboveInsetsState.addSource(navBarSource);
mAppWindow.mAboveInsetsState.addSource(statusBarSource);
final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
@@ -389,6 +388,50 @@ public class InsetsPolicyTest extends WindowTestsBase {
assertFalse(policy.isTransient(navigationBars()));
}
+ @Test
+ public void testFakeControlTarget_overrideVisibilityReceivedByWindows() {
+ final WindowState statusBar = addStatusBar();
+ final InsetsSourceProvider statusBarProvider = statusBar.getControllableInsetProvider();
+ statusBar.mSession.mCanForceShowingInsets = true;
+ statusBar.setHasSurface(true);
+ statusBarProvider.setServerVisible(true);
+
+ final InsetsSource statusBarSource = statusBarProvider.getSource();
+ final int statusBarId = statusBarSource.getId();
+ assertTrue(statusBarSource.isVisible());
+
+ final WindowState app1 = addWindow(TYPE_APPLICATION, "app1");
+ app1.mAboveInsetsState.addSource(statusBarSource);
+ assertTrue(app1.getInsetsState().peekSource(statusBarId).isVisible());
+
+ final WindowState app2 = addWindow(TYPE_APPLICATION, "app2");
+ app2.mAboveInsetsState.addSource(statusBarSource);
+ assertTrue(app2.getInsetsState().peekSource(statusBarId).isVisible());
+
+ app2.setRequestedVisibleTypes(0, navigationBars() | statusBars());
+ mDisplayContent.getInsetsPolicy().updateBarControlTarget(app2);
+ waitUntilWindowAnimatorIdle();
+
+ // app2 is the real control target now. It can override the visibility of all sources that
+ // it controls.
+ assertFalse(statusBarSource.isVisible());
+ assertFalse(app1.getInsetsState().peekSource(statusBarId).isVisible());
+ assertFalse(app2.getInsetsState().peekSource(statusBarId).isVisible());
+
+ statusBar.mAttrs.forciblyShownTypes = statusBars();
+ mDisplayContent.getDisplayPolicy().applyPostLayoutPolicyLw(
+ statusBar, statusBar.mAttrs, null, null);
+ mDisplayContent.getInsetsPolicy().updateBarControlTarget(app2);
+ waitUntilWindowAnimatorIdle();
+
+ // app2 is the fake control target now. It can only override the visibility of sources
+ // received by windows, but not the raw source.
+ assertTrue(statusBarSource.isVisible());
+ assertFalse(app1.getInsetsState().peekSource(statusBarId).isVisible());
+ assertFalse(app2.getInsetsState().peekSource(statusBarId).isVisible());
+
+ }
+
private WindowState addNavigationBar() {
final Binder owner = new Binder();
final WindowState win = createWindow(null, TYPE_NAVIGATION_BAR, "navBar");
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 114796d17ef1..2085d6140f68 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -367,9 +367,11 @@ public class InsetsStateControllerTest extends WindowTestsBase {
doReturn(rotatedState).when(app.mToken).getFixedRotationTransformInsetsState();
assertTrue(rotatedState.isSourceOrDefaultVisible(ID_STATUS_BAR, statusBars()));
- provider.getSource().setVisible(false);
+ app.setRequestedVisibleTypes(0, statusBars());
+ mDisplayContent.getInsetsPolicy().updateBarControlTarget(app);
mDisplayContent.getInsetsPolicy().showTransient(statusBars(),
true /* isGestureOnSystemBar */);
+ waitUntilWindowAnimatorIdle();
assertTrue(mDisplayContent.getInsetsPolicy().isTransient(statusBars()));
assertFalse(app.getInsetsState().isSourceOrDefaultVisible(ID_STATUS_BAR, statusBars()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
index 06033c7ebf75..3fcec963593c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
@@ -184,7 +184,7 @@ public class LetterboxConfigurationPersisterTest {
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
firstPersister.setLetterboxPositionForVerticalReachability(false,
LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
- waitForCompletion(mPersisterQueue);
+ waitForCompletion(firstPersisterQueue);
final int newPositionForHorizontalReachability =
firstPersister.getLetterboxPositionForHorizontalReachability(false);
final int newPositionForVerticalReachability =
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index d5afe3b2f078..03e0401013f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -2404,8 +2404,9 @@ public class SizeCompatTests extends WindowTestsBase {
.setUid(android.os.Process.myUid())
.build();
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
- activity.mWmService.mLetterboxConfiguration
- .setUserAppAspectRatioSettingsOverrideEnabled(enabled);
+ spyOn(activity.mWmService.mLetterboxConfiguration);
+ doReturn(enabled).when(activity.mWmService.mLetterboxConfiguration)
+ .isUserAppAspectRatioSettingsEnabled();
// Set user aspect ratio override
final IPackageManager pm = mAtm.getPackageManager();
try {
@@ -4244,6 +4245,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Set up a display in landscape with a fixed-orientation PORTRAIT app
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setIsAutomaticReachabilityInBookModeEnabled(false);
mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f);
prepareUnresizable(mActivity, 1.75f, SCREEN_ORIENTATION_PORTRAIT);
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
index 3870dfd17d50..4f99f14e4dc1 100644
--- a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
@@ -95,21 +95,29 @@ public class WallpaperEffectsGenerationPerUserService extends
String newTaskId = cinematicEffectRequest.getTaskId();
// Previous request is still being processed.
if (mCinematicEffectListenerWrapper != null) {
+ CinematicEffectResponse cinematicEffectResponse;
if (mCinematicEffectListenerWrapper.mTaskId.equals(newTaskId)) {
- invokeCinematicListenerAndCleanup(
- new CinematicEffectResponse.Builder(
- CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_PENDING, newTaskId)
- .build()
- );
+ cinematicEffectResponse = new CinematicEffectResponse.Builder(
+ CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_PENDING, newTaskId)
+ .build();
} else {
- invokeCinematicListenerAndCleanup(
- new CinematicEffectResponse.Builder(
- CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS,
- newTaskId).build()
- );
+ cinematicEffectResponse = new CinematicEffectResponse.Builder(
+ CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS,
+ newTaskId)
+ .build();
+ }
+ try {
+ cinematicEffectListener.onCinematicEffectGenerated(cinematicEffectResponse);
+ return;
+ } catch (RemoteException e) {
+ if (isDebug()) {
+ Slog.w(TAG, "RemoteException invoking cinematic effect listener for task["
+ + mCinematicEffectListenerWrapper.mTaskId + "]");
+ }
+ return;
}
- return;
}
+
RemoteWallpaperEffectsGenerationService remoteService = ensureRemoteServiceLocked();
if (remoteService != null) {
remoteService.executeOnResolvedService(