summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--StubLibraries.bp1
-rw-r--r--apex/media/Android.bp5
-rw-r--r--core/api/module-lib-lint-baseline.txt39
-rw-r--r--core/api/system-lint-baseline.txt238
-rw-r--r--core/java/android/app/IActivityManager.aidl8
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java220
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageImpl.java4
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java8
-rw-r--r--core/java/android/content/pm/parsing/ParsingUtils.java5
-rw-r--r--core/java/android/content/pm/verify/domain/TEST_MAPPING5
-rw-r--r--core/java/android/net/vcn/VcnGatewayConnectionConfig.java93
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java1
-rw-r--r--core/java/android/view/CrossWindowBlurListeners.java2
-rw-r--r--core/res/res/values-af/strings.xml3
-rw-r--r--core/res/res/values-am/strings.xml3
-rw-r--r--core/res/res/values-ar/strings.xml3
-rw-r--r--core/res/res/values-as/strings.xml3
-rw-r--r--core/res/res/values-az/strings.xml13
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml7
-rw-r--r--core/res/res/values-be/strings.xml3
-rw-r--r--core/res/res/values-bg/strings.xml3
-rw-r--r--core/res/res/values-bn/strings.xml33
-rw-r--r--core/res/res/values-bs/strings.xml2
-rw-r--r--core/res/res/values-ca/strings.xml2
-rw-r--r--core/res/res/values-da/strings.xml3
-rw-r--r--core/res/res/values-de/strings.xml3
-rw-r--r--core/res/res/values-es/strings.xml3
-rw-r--r--core/res/res/values-et/strings.xml3
-rw-r--r--core/res/res/values-eu/strings.xml5
-rw-r--r--core/res/res/values-fa/strings.xml3
-rw-r--r--core/res/res/values-fi/strings.xml3
-rw-r--r--core/res/res/values-fr-rCA/strings.xml3
-rw-r--r--core/res/res/values-fr/strings.xml2
-rw-r--r--core/res/res/values-gl/strings.xml5
-rw-r--r--core/res/res/values-gu/strings.xml3
-rw-r--r--core/res/res/values-hi/strings.xml5
-rw-r--r--core/res/res/values-hu/strings.xml3
-rw-r--r--core/res/res/values-hy/strings.xml3
-rw-r--r--core/res/res/values-in/strings.xml3
-rw-r--r--core/res/res/values-is/strings.xml5
-rw-r--r--core/res/res/values-it/strings.xml3
-rw-r--r--core/res/res/values-iw/strings.xml7
-rw-r--r--core/res/res/values-ja/strings.xml5
-rw-r--r--core/res/res/values-ka/strings.xml3
-rw-r--r--core/res/res/values-kk/strings.xml7
-rw-r--r--core/res/res/values-km/strings.xml3
-rw-r--r--core/res/res/values-kn/strings.xml3
-rw-r--r--core/res/res/values-ko/strings.xml3
-rw-r--r--core/res/res/values-ky/strings.xml3
-rw-r--r--core/res/res/values-lo/strings.xml3
-rw-r--r--core/res/res/values-lv/strings.xml3
-rw-r--r--core/res/res/values-mk/strings.xml7
-rw-r--r--core/res/res/values-ml/strings.xml5
-rw-r--r--core/res/res/values-mn/strings.xml3
-rw-r--r--core/res/res/values-mr/strings.xml3
-rw-r--r--core/res/res/values-my/strings.xml3
-rw-r--r--core/res/res/values-nb/strings.xml7
-rw-r--r--core/res/res/values-ne/strings.xml2
-rw-r--r--core/res/res/values-nl/strings.xml5
-rw-r--r--core/res/res/values-or/strings.xml3
-rw-r--r--core/res/res/values-pl/strings.xml9
-rw-r--r--core/res/res/values-ro/strings.xml3
-rw-r--r--core/res/res/values-ru/strings.xml6
-rw-r--r--core/res/res/values-si/strings.xml3
-rw-r--r--core/res/res/values-sk/strings.xml3
-rw-r--r--core/res/res/values-sl/strings.xml7
-rw-r--r--core/res/res/values-sq/strings.xml5
-rw-r--r--core/res/res/values-sr/strings.xml7
-rw-r--r--core/res/res/values-sv/strings.xml3
-rw-r--r--core/res/res/values-sw/strings.xml5
-rw-r--r--core/res/res/values-ta/strings.xml3
-rw-r--r--core/res/res/values-te/strings.xml3
-rw-r--r--core/res/res/values-th/strings.xml3
-rw-r--r--core/res/res/values-ur/strings.xml3
-rw-r--r--core/res/res/values-uz/strings.xml3
-rw-r--r--core/res/res/values-vi/strings.xml3
-rw-r--r--core/res/res/values-zh-rHK/strings.xml3
-rw-r--r--core/res/res/values-zh-rTW/strings.xml5
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/apks/overlay_config/Android.bp1
-rw-r--r--core/tests/coretests/apks/overlay_config/AndroidManifest.xml2
-rw-r--r--core/tests/coretests/apks/overlay_config/OWNERS1
-rw-r--r--core/tests/coretests/src/com/android/internal/content/res/OWNERS1
-rw-r--r--core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java (renamed from core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java)4
-rw-r--r--core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java (renamed from core/tests/coretests/src/com/android/internal/content/OverlayConfigTest.java)4
-rw-r--r--data/etc/car/com.android.car.shell.xml3
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java6
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings.xml6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java7
-rw-r--r--packages/PackageInstaller/res/values-eu/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-gl/strings.xml2
-rw-r--r--packages/Shell/res/values-az/strings.xml2
-rw-r--r--packages/StatementService/Android.bp19
-rw-r--r--packages/StatementService/AndroidManifest.xml61
-rw-r--r--packages/StatementService/src/com/android/statementservice/DirectStatementService.java293
-rw-r--r--packages/StatementService/src/com/android/statementservice/ExceptionLoggingFutureTask.java46
-rw-r--r--packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java212
-rw-r--r--packages/StatementService/src/com/android/statementservice/StatementServiceApplication.kt35
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/BaseDomainVerificationReceiver.kt41
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/BootCompletedReceiver.kt59
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt79
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV2.kt116
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/DomainVerificationUtils.kt77
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/DomainVerifier.kt146
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/VerifyStatus.kt66
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/worker/BaseRequestWorker.kt34
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt89
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/worker/RetryRequestWorker.kt79
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt87
-rw-r--r--packages/StatementService/src/com/android/statementservice/domain/worker/SingleV2RequestWorker.kt68
-rw-r--r--packages/StatementService/src/com/android/statementservice/network/retriever/StatementParser.kt109
-rw-r--r--packages/StatementService/src/com/android/statementservice/network/retriever/StatementRetriever.kt121
-rw-r--r--packages/StatementService/src/com/android/statementservice/network/retriever/UrlFetcher.kt86
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java3
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java108
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java26
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAssetMatcher.java2
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/AndroidPackageInfoFetcher.java93
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/AssetFactory.java12
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/AssetMatcherFactory.java10
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java213
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/ParsedStatement.java41
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/Statement.java11
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/StatementParser.java111
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java197
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/Utils.java159
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java14
-rw-r--r--packages/StatementService/src/com/android/statementservice/retriever/WebContent.java8
-rw-r--r--packages/StatementService/src/com/android/statementservice/utils/AndroidUtils.kt63
-rw-r--r--packages/StatementService/src/com/android/statementservice/utils/Result.kt33
-rw-r--r--packages/StatementService/src/com/android/statementservice/utils/StatementUtils.kt162
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java10
-rw-r--r--packages/SystemUI/res-keyguard/values-ne/strings.xml4
-rw-r--r--packages/SystemUI/res-product/values-ky/strings.xml16
-rw-r--r--packages/SystemUI/res/layout/controls_base_item.xml3
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml4
-rw-r--r--packages/SystemUI/res/layout/udfps_enroll_view.xml3
-rw-r--r--packages/SystemUI/res/layout/wallet_empty_state.xml2
-rw-r--r--packages/SystemUI/res/layout/wallet_fullscreen.xml7
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml2
-rw-r--r--packages/SystemUI/res/values-az/strings.xml8
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml2
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es/strings.xml2
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml4
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml4
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml2
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml2
-rw-r--r--packages/SystemUI/res/values-my/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml8
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-te/strings.xml4
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml8
-rw-r--r--packages/SystemUI/res/values/colors.xml1
-rw-r--r--packages/SystemUI/res/values/config.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml17
-rw-r--r--packages/SystemUI/res/values/strings.xml10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/LatencyTester.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java100
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java103
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java182
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt99
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java104
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values/strings.xml2
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java47
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java13
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java22
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java1
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java86
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java13
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java330
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java3
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java1
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java22
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING5
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java79
-rw-r--r--services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java8
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java3
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java15
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java31
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java79
-rw-r--r--services/tests/servicestests/Android.bp5
-rw-r--r--services/tests/servicestests/apks/install-split-base/AndroidManifest.xml7
-rw-r--r--services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml7
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java149
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java2
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java24
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthLte.java2
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthNr.java6
-rw-r--r--telephony/java/android/telephony/ServiceState.java30
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt17
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt10
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt23
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt27
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt11
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt23
-rw-r--r--tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java12
-rw-r--r--tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java3
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java2
275 files changed, 3768 insertions, 3017 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp
index e82a322c294e..941a1fa033e4 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -205,6 +205,7 @@ droidstubs {
api_lint: {
enabled: true,
new_since: ":android.api.module-lib.latest",
+ baseline_file: "core/api/module-lib-lint-baseline.txt",
},
},
dists: [
diff --git a/apex/media/Android.bp b/apex/media/Android.bp
index a75f1aed4ade..2b4b3f0f52e8 100644
--- a/apex/media/Android.bp
+++ b/apex/media/Android.bp
@@ -27,7 +27,6 @@ package {
sdk {
name: "media-module-sdk",
- java_sdk_libs: [
- "framework-media",
- ],
+ bootclasspath_fragments: ["com.android.media-bootclasspath-fragment"],
+ java_sdk_libs: ["service-media-s"],
}
diff --git a/core/api/module-lib-lint-baseline.txt b/core/api/module-lib-lint-baseline.txt
new file mode 100644
index 000000000000..0c1ebb3b2208
--- /dev/null
+++ b/core/api/module-lib-lint-baseline.txt
@@ -0,0 +1,39 @@
+// Baseline format: 1.0
+SamShouldBeLast: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.app.ActivityManager.addOnUidImportanceListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler):
+ SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, String):
+ SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, String, android.os.Bundle):
+ SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.app.PendingIntent#send(int, android.app.PendingIntent.OnFinished, android.os.Handler):
+ SAM-compatible parameters (such as parameter 2, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.AudioManager#abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes):
+ SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.abandonAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int):
+ SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy):
+ SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int):
+ SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName):
+ SAM-compatible parameters (such as parameter 1, "sessionListener", in android.media.session.MediaSessionManager.addOnActiveSessionsChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "sessionListener", in android.media.session.MediaSessionManager.addOnActiveSessionsChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.session.MediaSessionManager#addOnSession2TokensChangedListener(android.media.session.MediaSessionManager.OnSession2TokensChangedListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.session.MediaSessionManager.addOnSession2TokensChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.session.MediaSessionManager#setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.session.MediaSessionManager.setOnMediaKeyListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.session.MediaSessionManager#setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.session.MediaSessionManager.setOnVolumeKeyLongPressListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.os.Binder#attachInterface(android.os.IInterface, String):
+ SAM-compatible parameters (such as parameter 1, "owner", in android.os.Binder.attachInterface) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.os.Binder#linkToDeath(android.os.IBinder.DeathRecipient, int):
+ SAM-compatible parameters (such as parameter 1, "recipient", in android.os.Binder.linkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.os.Binder#unlinkToDeath(android.os.IBinder.DeathRecipient, int):
+ SAM-compatible parameters (such as parameter 1, "recipient", in android.os.Binder.unlinkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.os.IBinder#linkToDeath(android.os.IBinder.DeathRecipient, int):
+ SAM-compatible parameters (such as parameter 1, "recipient", in android.os.IBinder.linkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.os.IBinder#unlinkToDeath(android.os.IBinder.DeathRecipient, int):
+ SAM-compatible parameters (such as parameter 1, "recipient", in android.os.IBinder.unlinkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index 58f6c52d2b05..b435acfccde8 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -1,6 +1,6 @@
// Baseline format: 1.0
ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
-
+
BuilderSetStyle: android.net.IpSecTransform.Builder#buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex):
@@ -12,23 +12,23 @@ ExecutorRegistration: android.media.MediaPlayer#setOnRtpRxNoticeListener(android
GenericException: android.app.prediction.AppPredictor#finalize():
-
+
GenericException: android.hardware.location.ContextHubClient#finalize():
-
+
GenericException: android.net.IpSecManager.IpSecTunnelInterface#finalize():
-
+
GenericException: android.service.autofill.augmented.FillWindow#finalize():
-
+
IntentBuilderName: android.app.search.SearchAction#getIntent():
-
+
IntentBuilderName: android.app.smartspace.SmartspaceAction#getIntent():
Methods creating an Intent should be named `create<Foo>Intent()`, was `getIntent`
KotlinKeyword: android.app.Notification#when:
-
+
MissingGetterMatchingBuilder: android.security.keystore.KeyGenParameterSpec.Builder#setUid(int):
@@ -42,49 +42,49 @@ MissingGetterMatchingBuilder: android.telephony.mbms.DownloadRequest.Builder#set
MissingNullability: android.media.soundtrigger.SoundTriggerDetectionService#onUnbind(android.content.Intent) parameter #0:
-
+
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #0:
-
+
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #1:
-
+
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #2:
-
+
MissingNullability: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context) parameter #0:
-
+
MissingNullability: android.provider.ContactsContract.MetadataSync#CONTENT_URI:
-
+
MissingNullability: android.provider.ContactsContract.MetadataSync#METADATA_AUTHORITY_URI:
-
+
MissingNullability: android.provider.ContactsContract.MetadataSyncState#CONTENT_URI:
-
+
MissingNullability: android.provider.SearchIndexablesProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #0:
-
+
MissingNullability: android.provider.SearchIndexablesProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #1:
-
+
MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#onUnbind(android.content.Intent) parameter #0:
-
+
MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
-
+
MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
-
+
MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
-
+
MissingNullability: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context) parameter #0:
-
+
MissingNullability: android.telephony.NetworkService#onUnbind(android.content.Intent) parameter #0:
-
+
MissingNullability: android.telephony.SubscriptionPlan.Builder#createRecurringDaily(java.time.ZonedDateTime) parameter #0:
-
+
MissingNullability: android.telephony.SubscriptionPlan.Builder#createRecurringMonthly(java.time.ZonedDateTime) parameter #0:
-
+
MissingNullability: android.telephony.SubscriptionPlan.Builder#createRecurringWeekly(java.time.ZonedDateTime) parameter #0:
-
+
MissingNullability: android.telephony.data.DataService#onUnbind(android.content.Intent) parameter #0:
-
+
MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
-
+
MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String) parameter #0:
-
+
OnNameExpected: android.service.smartspace.SmartspaceService#notifySmartspaceEvent(android.app.smartspace.SmartspaceSessionId, android.app.smartspace.SmartspaceTargetEvent):
@@ -92,178 +92,192 @@ OnNameExpected: android.service.smartspace.SmartspaceService#notifySmartspaceEve
ProtectedMember: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context):
-
+
ProtectedMember: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
-
+
ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
-
+
SamShouldBeLast: android.accounts.AccountManager#addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean):
-
+
SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, String[]):
-
+
SamShouldBeLast: android.accounts.AccountManager#confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#editProperties(String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#getAuthToken(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#getAuthToken(android.accounts.Account, String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#getAuthToken(android.accounts.Account, String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#getAuthTokenByFeatures(String, String, String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#isCredentialsUpdateSuggested(android.accounts.Account, String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#renameAccount(android.accounts.Account, String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#startAddAccountSession(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#startUpdateCredentialsSession(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.accounts.AccountManager#updateCredentials(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+
SamShouldBeLast: android.app.AlarmManager#set(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler):
-
+
SamShouldBeLast: android.app.AlarmManager#setExact(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler):
-
+
SamShouldBeLast: android.app.AlarmManager#setWindow(int, long, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler):
-
+
SamShouldBeLast: android.app.WallpaperInfo#dump(android.util.Printer, String):
-
+
SamShouldBeLast: android.app.WallpaperManager#addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler):
-
+
SamShouldBeLast: android.app.admin.DevicePolicyManager#installSystemUpdate(android.content.ComponentName, android.net.Uri, java.util.concurrent.Executor, android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback):
-
+
SamShouldBeLast: android.content.IntentFilter#dump(android.util.Printer, String):
-
+
SamShouldBeLast: android.content.pm.ApplicationInfo#dump(android.util.Printer, String):
-
+
SamShouldBeLast: android.content.pm.PackageItemInfo#dumpBack(android.util.Printer, String):
-
+
SamShouldBeLast: android.content.pm.PackageItemInfo#dumpFront(android.util.Printer, String):
-
+
SamShouldBeLast: android.content.pm.ResolveInfo#dump(android.util.Printer, String):
-
+
SamShouldBeLast: android.location.Location#dump(android.util.Printer, String):
-
+
SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
-
+
SamShouldBeLast: android.location.LocationManager#registerGnssMeasurementsCallback(java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
-
+
SamShouldBeLast: android.location.LocationManager#registerGnssNavigationMessageCallback(java.util.concurrent.Executor, android.location.GnssNavigationMessage.Callback):
-
+
SamShouldBeLast: android.location.LocationManager#registerGnssStatusCallback(java.util.concurrent.Executor, android.location.GnssStatus.Callback):
-
+
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
-
+
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, java.util.concurrent.Executor, android.location.LocationListener):
-
+
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, java.util.concurrent.Executor, android.location.LocationListener):
-
+
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
-
+
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, java.util.concurrent.Executor, android.location.LocationListener):
-
+
SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
-
+
SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
-
+
SamShouldBeLast: android.media.AudioFocusRequest.Builder#setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler):
-
+
SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int):
-
+
SamShouldBeLast: android.media.AudioRecord#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
+
SamShouldBeLast: android.media.AudioRecord#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
-
+
SamShouldBeLast: android.media.AudioRecordingMonitor#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
-
+
SamShouldBeLast: android.media.AudioRouting#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
+
SamShouldBeLast: android.media.AudioTrack#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
+
+SamShouldBeLast: android.media.MediaPlayer#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.MediaPlayer#setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.setOnDrmInfoListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.MediaPlayer#setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.setOnDrmPreparedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.MediaPlayer#setOnMediaTimeDiscontinuityListener(android.media.MediaPlayer.OnMediaTimeDiscontinuityListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.setOnMediaTimeDiscontinuityListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
SAM-compatible parameters (such as parameter 2, "listener", in android.media.MediaPlayer.setOnRtpRxNoticeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.MediaPlayer#setOnSubtitleDataListener(android.media.MediaPlayer.OnSubtitleDataListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.setOnSubtitleDataListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.MediaRecorder#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
+
SamShouldBeLast: android.media.MediaRecorder#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
-
+
SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName):
-
+
SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler):
-
+
SamShouldBeLast: android.media.session.MediaSessionManager#addOnSession2TokensChangedListener(android.media.session.MediaSessionManager.OnSession2TokensChangedListener, android.os.Handler):
-
+
SamShouldBeLast: android.media.session.MediaSessionManager#registerCallback(java.util.concurrent.Executor, android.media.session.MediaSessionManager.Callback):
-
+
SamShouldBeLast: android.nfc.NfcAdapter#enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle):
-
+
SamShouldBeLast: android.nfc.NfcAdapter#ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler):
-
+
SamShouldBeLast: android.nfc.NfcAdapter#setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity):
-
+
SamShouldBeLast: android.nfc.NfcAdapter#setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...):
-
+
SamShouldBeLast: android.nfc.NfcAdapter#setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...):
-
+
SamShouldBeLast: android.os.Binder#attachInterface(android.os.IInterface, String):
-
+
SamShouldBeLast: android.os.Binder#linkToDeath(android.os.IBinder.DeathRecipient, int):
-
+
SamShouldBeLast: android.os.Binder#unlinkToDeath(android.os.IBinder.DeathRecipient, int):
-
+
SamShouldBeLast: android.os.Handler#dump(android.util.Printer, String):
-
+
SamShouldBeLast: android.os.Handler#postAtTime(Runnable, Object, long):
-
+
SamShouldBeLast: android.os.Handler#postAtTime(Runnable, long):
-
+
SamShouldBeLast: android.os.Handler#postDelayed(Runnable, Object, long):
-
+
SamShouldBeLast: android.os.Handler#postDelayed(Runnable, long):
-
+
SamShouldBeLast: android.os.Handler#removeCallbacks(Runnable, Object):
-
+
SamShouldBeLast: android.os.IBinder#linkToDeath(android.os.IBinder.DeathRecipient, int):
-
+
SamShouldBeLast: android.os.IBinder#unlinkToDeath(android.os.IBinder.DeathRecipient, int):
-
+
SamShouldBeLast: android.os.RecoverySystem#verifyPackage(java.io.File, android.os.RecoverySystem.ProgressListener, java.io.File):
-
+
+SamShouldBeLast: android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, String[], java.security.Principal[], String, int, String):
+ SAM-compatible parameters (such as parameter 2, "response", in android.security.KeyChain.choosePrivateKeyAlias) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, String[], java.security.Principal[], android.net.Uri, String):
+ SAM-compatible parameters (such as parameter 2, "response", in android.security.KeyChain.choosePrivateKeyAlias) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.View#postDelayed(Runnable, long):
-
+
SamShouldBeLast: android.view.View#postOnAnimationDelayed(Runnable, long):
-
+
SamShouldBeLast: android.view.View#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long):
-
+
SamShouldBeLast: android.view.Window#addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler):
-
+
SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, android.os.Handler):
-
+
SamShouldBeLast: android.view.accessibility.AccessibilityManager#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler):
-
+
SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams):
-
+
UserHandleName: android.app.search.SearchAction.Builder#setUserHandle(android.os.UserHandle):
Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `setUserHandle`
UserHandleName: android.app.search.SearchTarget.Builder#setUserHandle(android.os.UserHandle):
-
+
UserHandleName: android.app.smartspace.SmartspaceAction.Builder#setUserHandle(android.os.UserHandle):
Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `setUserHandle`
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 89d90a3b9d6f..313a34067cd0 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -686,6 +686,14 @@ interface IActivityManager {
boolean enableAppFreezer(in boolean enable);
/**
+ * Suppress or reenable the rate limit on foreground service notification deferral.
+ * This is for use within CTS and is protected by android.permission.WRITE_DEVICE_CONFIG.
+ *
+ * @param enable false to suppress rate-limit policy; true to reenable it.
+ */
+ boolean enableFgsNotificationRateLimit(in boolean enable);
+
+ /**
* Holds the AM lock for the specified amount of milliseconds.
* This is intended for use by the tests that need to imitate lock contention.
* The token should be obtained by
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 5887047728a6..76b98659067f 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -19,6 +19,9 @@ package android.content.pm.parsing;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.content.pm.parsing.ParsingPackageUtils.validateName;
+import static android.content.pm.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+import static android.content.pm.parsing.ParsingUtils.DEFAULT_MIN_SDK_VERSION;
+import static android.content.pm.parsing.ParsingUtils.DEFAULT_TARGET_SDK_VERSION;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.annotation.NonNull;
@@ -31,6 +34,7 @@ import android.content.pm.parsing.result.ParseResult;
import android.content.res.ApkAssets;
import android.content.res.XmlResourceParser;
import android.os.Trace;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Pair;
@@ -59,10 +63,6 @@ public class ApkLiteParseUtils {
private static final String TAG = ParsingUtils.TAG;
- // TODO(b/135203078): Consolidate constants
- private static final int DEFAULT_MIN_SDK_VERSION = 1;
- private static final int DEFAULT_TARGET_SDK_VERSION = 0;
-
private static final int PARSE_DEFAULT_INSTALL_LOCATION =
PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
@@ -323,8 +323,7 @@ public class ApkLiteParseUtils {
signingDetails = PackageParser.SigningDetails.UNKNOWN;
}
- final AttributeSet attrs = parser;
- return parseApkLite(input, apkPath, parser, attrs, signingDetails);
+ return parseApkLite(input, apkPath, parser, signingDetails);
} catch (XmlPullParserException | IOException | RuntimeException e) {
Slog.w(TAG, "Failed to parse " + apkPath, e);
return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -342,32 +341,39 @@ public class ApkLiteParseUtils {
}
private static ParseResult<ApkLite> parseApkLite(ParseInput input, String codePath,
- XmlPullParser parser, AttributeSet attrs, PackageParser.SigningDetails signingDetails)
+ XmlResourceParser parser, PackageParser.SigningDetails signingDetails)
throws IOException, XmlPullParserException {
- ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser, attrs);
+ ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser);
if (result.isError()) {
return input.error(result);
}
Pair<String, String> packageSplit = result.getResult();
- int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
- int versionCode = 0;
- int versionCodeMajor = 0;
+ int installLocation = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE,
+ "installLocation", PARSE_DEFAULT_INSTALL_LOCATION);
+ int versionCode = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "versionCode", 0);
+ int versionCodeMajor = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE,
+ "versionCodeMajor",
+ 0);
+ int revisionCode = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "revisionCode", 0);
+ boolean coreApp = parser.getAttributeBooleanValue("", "coreApp", false);
+ boolean isolatedSplits = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+ "isolatedSplits", false);
+ boolean isFeatureSplit = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+ "isFeatureSplit", false);
+ boolean isSplitRequired = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+ "isSplitRequired", false);
+ String configForSplit = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "configForSplit");
+
int targetSdkVersion = DEFAULT_TARGET_SDK_VERSION;
int minSdkVersion = DEFAULT_MIN_SDK_VERSION;
- int revisionCode = 0;
- boolean coreApp = false;
boolean debuggable = false;
boolean profilableByShell = false;
boolean multiArch = false;
boolean use32bitAbi = false;
boolean extractNativeLibs = true;
- boolean isolatedSplits = false;
- boolean isFeatureSplit = false;
- boolean isSplitRequired = false;
boolean useEmbeddedDex = false;
- String configForSplit = null;
String usesSplitName = null;
String targetPackage = null;
boolean overlayIsStatic = false;
@@ -377,40 +383,6 @@ public class ApkLiteParseUtils {
String requiredSystemPropertyName = null;
String requiredSystemPropertyValue = null;
- for (int i = 0; i < attrs.getAttributeCount(); i++) {
- final String attr = attrs.getAttributeName(i);
- switch (attr) {
- case "installLocation":
- installLocation = attrs.getAttributeIntValue(i,
- PARSE_DEFAULT_INSTALL_LOCATION);
- break;
- case "versionCode":
- versionCode = attrs.getAttributeIntValue(i, 0);
- break;
- case "versionCodeMajor":
- versionCodeMajor = attrs.getAttributeIntValue(i, 0);
- break;
- case "revisionCode":
- revisionCode = attrs.getAttributeIntValue(i, 0);
- break;
- case "coreApp":
- coreApp = attrs.getAttributeBooleanValue(i, false);
- break;
- case "isolatedSplits":
- isolatedSplits = attrs.getAttributeBooleanValue(i, false);
- break;
- case "configForSplit":
- configForSplit = attrs.getAttributeValue(i);
- break;
- case "isFeatureSplit":
- isFeatureSplit = attrs.getAttributeBooleanValue(i, false);
- break;
- case "isSplitRequired":
- isSplitRequired = attrs.getAttributeBooleanValue(i, false);
- break;
- }
- }
-
// Only search the tree when the tag is the direct child of <manifest> tag
int type;
final int searchDepth = parser.getDepth() + 1;
@@ -427,34 +399,23 @@ public class ApkLiteParseUtils {
}
if (ParsingPackageUtils.TAG_PACKAGE_VERIFIER.equals(parser.getName())) {
- final VerifierInfo verifier = parseVerifier(attrs);
+ final VerifierInfo verifier = parseVerifier(parser);
if (verifier != null) {
verifiers.add(verifier);
}
} else if (ParsingPackageUtils.TAG_APPLICATION.equals(parser.getName())) {
- for (int i = 0; i < attrs.getAttributeCount(); ++i) {
- final String attr = attrs.getAttributeName(i);
- switch (attr) {
- case "debuggable":
- debuggable = attrs.getAttributeBooleanValue(i, false);
- break;
- case "multiArch":
- multiArch = attrs.getAttributeBooleanValue(i, false);
- break;
- case "use32bitAbi":
- use32bitAbi = attrs.getAttributeBooleanValue(i, false);
- break;
- case "extractNativeLibs":
- extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
- break;
- case "useEmbeddedDex":
- useEmbeddedDex = attrs.getAttributeBooleanValue(i, false);
- break;
- case "rollbackDataPolicy":
- rollbackDataPolicy = attrs.getAttributeIntValue(i, 0);
- break;
- }
- }
+ debuggable = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "debuggable",
+ false);
+ multiArch = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "multiArch",
+ false);
+ use32bitAbi = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "use32bitAbi",
+ false);
+ extractNativeLibs = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+ "extractNativeLibs", true);
+ useEmbeddedDex = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+ "useEmbeddedDex", false);
+ rollbackDataPolicy = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE,
+ "rollbackDataPolicy", 0);
final int innerDepth = parser.getDepth();
int innerType;
@@ -470,52 +431,79 @@ public class ApkLiteParseUtils {
}
if (ParsingPackageUtils.TAG_PROFILEABLE.equals(parser.getName())) {
- for (int i = 0; i < attrs.getAttributeCount(); ++i) {
- final String attr = attrs.getAttributeName(i);
- if ("shell".equals(attr)) {
- profilableByShell = attrs.getAttributeBooleanValue(i,
- profilableByShell);
- }
- }
+ profilableByShell = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+ "shell", profilableByShell);
}
}
} else if (ParsingPackageUtils.TAG_OVERLAY.equals(parser.getName())) {
- for (int i = 0; i < attrs.getAttributeCount(); ++i) {
- final String attr = attrs.getAttributeName(i);
- if ("requiredSystemPropertyName".equals(attr)) {
- requiredSystemPropertyName = attrs.getAttributeValue(i);
- } else if ("requiredSystemPropertyValue".equals(attr)) {
- requiredSystemPropertyValue = attrs.getAttributeValue(i);
- } else if ("targetPackage".equals(attr)) {
- targetPackage = attrs.getAttributeValue(i);;
- } else if ("isStatic".equals(attr)) {
- overlayIsStatic = attrs.getAttributeBooleanValue(i, false);
- } else if ("priority".equals(attr)) {
- overlayPriority = attrs.getAttributeIntValue(i, 0);
- }
- }
+ requiredSystemPropertyName = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
+ "requiredSystemPropertyName");
+ requiredSystemPropertyValue = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
+ "requiredSystemPropertyValue");
+ targetPackage = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "targetPackage");
+ overlayIsStatic = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "isStatic",
+ false);
+ overlayPriority = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "priority", 0);
} else if (ParsingPackageUtils.TAG_USES_SPLIT.equals(parser.getName())) {
if (usesSplitName != null) {
Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
continue;
}
- usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name");
+ usesSplitName = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name");
if (usesSplitName == null) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"<uses-split> tag requires 'android:name' attribute");
}
} else if (ParsingPackageUtils.TAG_USES_SDK.equals(parser.getName())) {
- for (int i = 0; i < attrs.getAttributeCount(); ++i) {
- final String attr = attrs.getAttributeName(i);
- if ("targetSdkVersion".equals(attr)) {
- targetSdkVersion = attrs.getAttributeIntValue(i,
- DEFAULT_TARGET_SDK_VERSION);
+ // Mirrors ParsingPackageUtils#parseUsesSdk until lite and full parsing is combined
+ String minSdkVersionString = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
+ "minSdkVersion");
+ String targetSdkVersionString = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
+ "targetSdkVersion");
+
+ int minVer = DEFAULT_MIN_SDK_VERSION;
+ String minCode = null;
+ int targetVer = DEFAULT_TARGET_SDK_VERSION;
+ String targetCode = null;
+
+ if (!TextUtils.isEmpty(minSdkVersionString)) {
+ try {
+ minVer = Integer.parseInt(minSdkVersionString);
+ } catch (NumberFormatException ignored) {
+ minCode = minSdkVersionString;
}
- if ("minSdkVersion".equals(attr)) {
- minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
+ }
+
+ if (!TextUtils.isEmpty(targetSdkVersionString)) {
+ try {
+ targetVer = Integer.parseInt(targetSdkVersionString);
+ } catch (NumberFormatException ignored) {
+ targetCode = targetSdkVersionString;
+ if (minCode == null) {
+ minCode = targetCode;
+ }
}
+ } else {
+ targetVer = minVer;
+ targetCode = minCode;
}
+
+ ParseResult<Integer> targetResult = ParsingPackageUtils.computeTargetSdkVersion(
+ targetVer, targetCode, ParsingPackageUtils.SDK_CODENAMES, input);
+ if (targetResult.isError()) {
+ return input.error(targetResult);
+ }
+
+ ParseResult<Integer> minResult = ParsingPackageUtils.computeMinSdkVersion(
+ minVer, minCode, ParsingPackageUtils.SDK_VERSION,
+ ParsingPackageUtils.SDK_CODENAMES, input);
+ if (minResult.isError()) {
+ return input.error(minResult);
+ }
+
+ targetSdkVersion = targetResult.getResult();
+ minSdkVersion = minResult.getResult();
}
}
@@ -541,7 +529,7 @@ public class ApkLiteParseUtils {
}
public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input,
- XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException {
+ XmlResourceParser parser) throws IOException, XmlPullParserException {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
@@ -556,7 +544,7 @@ public class ApkLiteParseUtils {
"No <manifest> tag");
}
- final String packageName = attrs.getAttributeValue(null, "package");
+ final String packageName = parser.getAttributeValue(null, "package");
if (!"android".equals(packageName)) {
final ParseResult<?> nameResult = validateName(input, packageName, true, true);
if (nameResult.isError()) {
@@ -565,7 +553,7 @@ public class ApkLiteParseUtils {
}
}
- String splitName = attrs.getAttributeValue(null, "split");
+ String splitName = parser.getAttributeValue(null, "split");
if (splitName != null) {
if (splitName.length() == 0) {
splitName = null;
@@ -583,22 +571,8 @@ public class ApkLiteParseUtils {
}
public static VerifierInfo parseVerifier(AttributeSet attrs) {
- String packageName = null;
- String encodedPublicKey = null;
-
- final int attrCount = attrs.getAttributeCount();
- for (int i = 0; i < attrCount; i++) {
- final int attrResId = attrs.getAttributeNameResource(i);
- switch (attrResId) {
- case R.attr.name:
- packageName = attrs.getAttributeValue(i);
- break;
-
- case R.attr.publicKey:
- encodedPublicKey = attrs.getAttributeValue(i);
- break;
- }
- }
+ String packageName = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "name");
+ String encodedPublicKey = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "publicKey");
if (packageName == null || packageName.length() == 0) {
Slog.i(TAG, "verifier package name was null; skipping");
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index f0b76499093c..4c44ba1fc9ef 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -356,7 +356,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
private float minAspectRatio;
@Nullable
private SparseIntArray minExtensionVersions;
- private int minSdkVersion;
+ private int minSdkVersion = ParsingUtils.DEFAULT_MIN_SDK_VERSION;
private int networkSecurityConfigRes;
@Nullable
private CharSequence nonLocalizedLabel;
@@ -369,7 +369,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
private int requiresSmallestWidthDp;
private int roundIconRes;
private int targetSandboxVersion;
- private int targetSdkVersion;
+ private int targetSdkVersion = ParsingUtils.DEFAULT_TARGET_SDK_VERSION;
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
private String taskAffinity;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index b74760ac8bc4..6fd533355aad 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -582,12 +582,12 @@ public class ParsingPackageUtils {
*/
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
- throws XmlPullParserException, IOException, PackageParserException {
+ throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
ParseResult<Pair<String, String>> packageSplitResult =
- ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser);
+ ApkLiteParseUtils.parsePackageSplitNames(input, parser);
if (packageSplitResult.isError()) {
return input.error(packageSplitResult);
}
@@ -1460,9 +1460,9 @@ public class ParsingPackageUtils {
if (SDK_VERSION > 0) {
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
try {
- int minVers = 1;
+ int minVers = ParsingUtils.DEFAULT_MIN_SDK_VERSION;
String minCode = null;
- int targetVers = 0;
+ int targetVers = ParsingUtils.DEFAULT_TARGET_SDK_VERSION;
String targetCode = null;
TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java
index 5da5fbf4d8a7..07ec6a80c283 100644
--- a/core/java/android/content/pm/parsing/ParsingUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingUtils.java
@@ -35,6 +35,11 @@ public class ParsingUtils {
public static final String TAG = "PackageParsing";
+ public static final String ANDROID_RES_NAMESPACE = "http://schemas.android.com/apk/res/android";
+
+ public static final int DEFAULT_MIN_SDK_VERSION = 1;
+ public static final int DEFAULT_TARGET_SDK_VERSION = 0;
+
@Nullable
public static String buildClassName(String pkg, CharSequence clsSeq) {
if (clsSeq == null || clsSeq.length() <= 0) {
diff --git a/core/java/android/content/pm/verify/domain/TEST_MAPPING b/core/java/android/content/pm/verify/domain/TEST_MAPPING
index 5fcf4118ddd1..ba4a62cdbbf1 100644
--- a/core/java/android/content/pm/verify/domain/TEST_MAPPING
+++ b/core/java/android/content/pm/verify/domain/TEST_MAPPING
@@ -9,7 +9,10 @@
]
},
{
- "name": "CtsDomainVerificationDeviceTestCases"
+ "name": "CtsDomainVerificationDeviceStandaloneTestCases"
+ },
+ {
+ "name": "CtsDomainVerificationDeviceMultiUserTestCases"
},
{
"name": "CtsDomainVerificationHostTestCases"
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 7eea0b1129cf..86cd23d1e942 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -166,9 +166,6 @@ public final class VcnGatewayConnectionConfig {
private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
@NonNull private final SortedSet<Integer> mExposedCapabilities;
- private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities";
- @NonNull private final SortedSet<Integer> mUnderlyingCapabilities;
-
private static final String MAX_MTU_KEY = "mMaxMtu";
private final int mMaxMtu;
@@ -180,13 +177,11 @@ public final class VcnGatewayConnectionConfig {
@NonNull String gatewayConnectionName,
@NonNull IkeTunnelConnectionParams tunnelConnectionParams,
@NonNull Set<Integer> exposedCapabilities,
- @NonNull Set<Integer> underlyingCapabilities,
@NonNull long[] retryIntervalsMs,
@IntRange(from = MIN_MTU_V6) int maxMtu) {
mGatewayConnectionName = gatewayConnectionName;
mTunnelConnectionParams = tunnelConnectionParams;
mExposedCapabilities = new TreeSet(exposedCapabilities);
- mUnderlyingCapabilities = new TreeSet(underlyingCapabilities);
mRetryIntervalsMs = retryIntervalsMs;
mMaxMtu = maxMtu;
@@ -203,16 +198,12 @@ public final class VcnGatewayConnectionConfig {
final PersistableBundle exposedCapsBundle =
in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY);
- final PersistableBundle underlyingCapsBundle =
- in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY);
mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY);
mTunnelConnectionParams =
TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle);
mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
- mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
- underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
mMaxMtu = in.getInt(MAX_MTU_KEY);
@@ -312,36 +303,6 @@ public final class VcnGatewayConnectionConfig {
}
/**
- * Returns all capabilities required of underlying networks.
- *
- * <p>The returned integer-value capabilities will be sorted in ascending numerical order.
- *
- * @see Builder#addRequiredUnderlyingCapability(int)
- * @see Builder#removeRequiredUnderlyingCapability(int)
- * @hide
- */
- // TODO(b/182219992): Remove, and add when per-transport capabilities are supported
- @NonNull
- public int[] getRequiredUnderlyingCapabilities() {
- // Sorted set guarantees ordering
- return ArrayUtils.convertToIntArray(new ArrayList<>(mUnderlyingCapabilities));
- }
-
- /**
- * Returns all capabilities required of underlying networks.
- *
- * <p>Left to prevent the need to make major changes while changes are actively in flight.
- *
- * @deprecated use getRequiredUnderlyingCapabilities() instead
- * @hide
- */
- @Deprecated
- @NonNull
- public Set<Integer> getAllUnderlyingCapabilities() {
- return Collections.unmodifiableSet(mUnderlyingCapabilities);
- }
-
- /**
* Retrieves the configured retry intervals.
*
* @see Builder#setRetryIntervalsMillis(long[])
@@ -377,15 +338,10 @@ public final class VcnGatewayConnectionConfig {
PersistableBundleUtils.fromList(
new ArrayList<>(mExposedCapabilities),
PersistableBundleUtils.INTEGER_SERIALIZER);
- final PersistableBundle underlyingCapsBundle =
- PersistableBundleUtils.fromList(
- new ArrayList<>(mUnderlyingCapabilities),
- PersistableBundleUtils.INTEGER_SERIALIZER);
result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle);
result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
- result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle);
result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
result.putInt(MAX_MTU_KEY, mMaxMtu);
@@ -397,7 +353,6 @@ public final class VcnGatewayConnectionConfig {
return Objects.hash(
mGatewayConnectionName,
mExposedCapabilities,
- mUnderlyingCapabilities,
Arrays.hashCode(mRetryIntervalsMs),
mMaxMtu);
}
@@ -411,7 +366,6 @@ public final class VcnGatewayConnectionConfig {
final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
return mGatewayConnectionName.equals(rhs.mGatewayConnectionName)
&& mExposedCapabilities.equals(rhs.mExposedCapabilities)
- && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities)
&& Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
&& mMaxMtu == rhs.mMaxMtu;
}
@@ -423,7 +377,6 @@ public final class VcnGatewayConnectionConfig {
@NonNull private final String mGatewayConnectionName;
@NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams;
@NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
- @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
@NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
private int mMaxMtu = DEFAULT_MAX_MTU;
@@ -495,51 +448,6 @@ public final class VcnGatewayConnectionConfig {
}
/**
- * Require a capability for Networks underlying this VCN Gateway Connection.
- *
- * @param underlyingCapability the capability that a network MUST have in order to be an
- * underlying network for this VCN Gateway Connection.
- * @return this {@link Builder} instance, for chaining
- * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
- * networks
- * @hide
- */
- // TODO(b/182219992): Remove, and add when per-transport capabilities are supported
- @NonNull
- public Builder addRequiredUnderlyingCapability(
- @VcnSupportedCapability int underlyingCapability) {
- checkValidCapability(underlyingCapability);
-
- mUnderlyingCapabilities.add(underlyingCapability);
- return this;
- }
-
- /**
- * Remove a requirement of a capability for Networks underlying this VCN Gateway Connection.
- *
- * <p>Calling this method will allow Networks that do NOT have this capability to be
- * selected as an underlying network for this VCN Gateway Connection. However, underlying
- * networks MAY still have the removed capability.
- *
- * @param underlyingCapability the capability that a network DOES NOT need to have in order
- * to be an underlying network for this VCN Gateway Connection.
- * @return this {@link Builder} instance, for chaining
- * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
- * networks
- * @hide
- */
- // TODO(b/182219992): Remove, and add when per-transport capabilities are supported
- @NonNull
- @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap
- public Builder removeRequiredUnderlyingCapability(
- @VcnSupportedCapability int underlyingCapability) {
- checkValidCapability(underlyingCapability);
-
- mUnderlyingCapabilities.remove(underlyingCapability);
- return this;
- }
-
- /**
* Set the retry interval between VCN establishment attempts upon successive failures.
*
* <p>The last retry interval will be repeated until safe mode is entered, or a connection
@@ -603,7 +511,6 @@ public final class VcnGatewayConnectionConfig {
mGatewayConnectionName,
mTunnelConnectionParams,
mExposedCapabilities,
- mUnderlyingCapabilities,
mRetryIntervalsMs,
mMaxMtu);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 085136ea7ae9..941e9aa929f5 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1764,6 +1764,7 @@ public abstract class WallpaperService extends Service {
float finalStep = step;
int finalPageIndx = pageIndx;
Bitmap screenShot = page.getBitmap();
+ if (screenShot == null) screenShot = mLastScreenshot;
if (screenShot == null || screenShot.isRecycled()) {
if (DEBUG) {
Log.d(TAG, "invalid bitmap " + screenShot
diff --git a/core/java/android/view/CrossWindowBlurListeners.java b/core/java/android/view/CrossWindowBlurListeners.java
index 55fc4f41f5eb..e307b969ef91 100644
--- a/core/java/android/view/CrossWindowBlurListeners.java
+++ b/core/java/android/view/CrossWindowBlurListeners.java
@@ -42,7 +42,7 @@ public final class CrossWindowBlurListeners {
// property for background blur support in surface flinger
private static final String BLUR_PROPERTY = "ro.surface_flinger.supports_background_blur";
public static final boolean CROSS_WINDOW_BLUR_SUPPORTED =
- SystemProperties.get(BLUR_PROPERTY, "default").equals("1");
+ SystemProperties.getBoolean(BLUR_PROPERTY, false);
private static volatile CrossWindowBlurListeners sInstance;
private static final Object sLock = new Object();
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 215ec91af53b..ece2dc777575 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Opgedateer deur jou administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Uitgevee deur jou administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte, sekere kenmerke en sommige netwerkverbindings af"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte, sekere kenmerke en sommige netwerkverbindings af"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys voordat jy op hulle tik nie."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Skakel Databespaarder aan?"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index dff40b6a7f1d..5bfd8d591dd4 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"እሺ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ባትሪ ቆጣቢ ጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ ዕይታዊ ውጤቶችን፣ አንዳንድ ባህሪዎችን፣ እና አንዳንድ የአውታረ መረብ ግንኙነቶችን ይገድባል ወይም ያጠፋል።"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"ባትሪ ቆጣቢ ጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ ዕይታዊ ውጤቶችን፣ አንዳንድ ባህሪዎችን፣ እና አንዳንድ የአውታረ መረብ ግንኙነቶችን ይገድባል ወይም ያጠፋል።"</string>
<string name="data_saver_description" msgid="4995164271550590517">"የውሂብ አጠቃቀም እንዲቀንስ ለማገዝ ውሂብ ቆጣቢ አንዳንድ መተግበሪያዎች ከበስተጀርባ ሆነው ውሂብ እንዳይልኩ ወይም እንዳይቀበሉ ይከለክላቸዋል። በአሁኑ ጊዜ እየተጠቀሙበት ያለ መተግበሪያ ውሂብ ሊደርስ ይችላል፣ ነገር ግን ባነሰ ተደጋጋሚነት ሊሆን ይችላል። ይሄ ማለት ለምሳሌ ምስሎችን መታ እስኪያደርጓቸው ድረስ ላይታዩ ይችላሉ ማለት ነው።"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ውሂብ ቆጣቢ ይጥፋ?"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c88218d99e5f..77d3e6066100 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1958,8 +1958,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"تم التحديث بواسطة المشرف"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"تم الحذف بواسطة المشرف"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة وبعض اتصالات الشبكات."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة وبعض اتصالات الشبكات."</string>
<string name="data_saver_description" msgid="4995164271550590517">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيقات المتاحة لديك الآن استخدام البيانات، ولكن لا يمكنها الإكثار من ذلك. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"هل تريد تفعيل توفير البيانات؟"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 20740abfc24c..5802c4135af1 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপোনাৰ প্ৰশাসকে আপেডট কৰিছে"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপোনাৰ প্ৰশাসকে মচিছে"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট, নিৰ্দিষ্ট কিছুমান সুবিধা আৰু নেটৱৰ্কৰ সংযোগ সীমিত অথবা অফ কৰে।"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট, নিৰ্দিষ্ট কিছুমান সুবিধা আৰু নেটৱৰ্কৰ সংযোগ অফ কৰে অথবা সীমাবদ্ধ কৰে।"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ডেটা ব্য়ৱহাৰৰ হ্ৰাস কৰিবলৈ ডেটা সঞ্চয়কাৰীয়ে কিছুমান এপক নেপথ্য়ত ডেটা প্ৰেৰণ বা সংগ্ৰহ কৰাত বাধা প্ৰদান কৰে। আপুনি বৰ্তমান ব্য়ৱহাৰ কৰি থকা এটা এপে ডেটা এক্সেছ কৰিব পাৰে, কিন্তু সঘনাই এক্সেছ কৰিব নোৱাৰিব পাৰে। ইয়াৰ অৰ্থ উদাহৰণস্বৰূপে এয়া হ\'ব পাৰে যে, আপুনি নিটিপা পর্যন্ত প্ৰতিচ্ছবিসমূহ দেখুওৱা নহ’ব।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সঞ্চয়কাৰী অন কৰিবনে?"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 8db8251c789b..79043149b907 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1157,7 +1157,7 @@
<string name="redo" msgid="7231448494008532233">"Yenidən edin"</string>
<string name="autofill" msgid="511224882647795296">"Avtodoldurma"</string>
<string name="textSelectionCABTitle" msgid="5151441579532476940">"Mətn seçimi"</string>
- <string name="addToDictionary" msgid="8041821113480950096">"Lüğətə əlavə et"</string>
+ <string name="addToDictionary" msgid="8041821113480950096">"Lüğətə əlavə edin"</string>
<string name="deleteText" msgid="4200807474529938112">"Sil"</string>
<string name="inputMethod" msgid="1784759500516314751">"Daxiletmə metodu"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Mətn əməliyyatları"</string>
@@ -1366,8 +1366,8 @@
<string name="usb_power_notification_message" msgid="7284765627437897702">"Qoşulmuş cihaza enerji doldurulur. Əlavə seçimlər üçün klikləyin."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Analoq audio aksesuar aşkarlandı"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Əlavə edilən cihaz bu telefonla uyğun deyil. Ətraflı məlumat üçün klikləyin."</string>
- <string name="adb_active_notification_title" msgid="408390247354560331">"USB sazlama qoşuludur"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"USB sazlamanı deaktiv etmək üçün klikləyin"</string>
+ <string name="adb_active_notification_title" msgid="408390247354560331">"USB vasitəsilə sazlama qoşuludur"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Deaktiv etmək üçün klikləyin"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USb debaqı deaktivasiya etməyi seçin."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"WiFi sazlaması qoşulub"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"WiFi sazlamasını deaktiv etmək üçün toxunun"</string>
@@ -1387,7 +1387,7 @@
<string name="share_remote_bugreport_action" msgid="7630880678785123682">"PAYLAŞIN"</string>
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RƏDD EDİN"</string>
<string name="select_input_method" msgid="3971267998568587025">"Daxiletmə metodunu seçin"</string>
- <string name="show_ime" msgid="6406112007347443383">"Fiziki klaviatura aktiv olduğu halda ekranda saxlayın"</string>
+ <string name="show_ime" msgid="6406112007347443383">"Fiziki klaviatura aktiv olanda görünsün"</string>
<string name="hardware" msgid="1800597768237606953">"Virtual klaviaturanı göstərin"</string>
<string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"Fiziki klaviaturanı konfiqurasiya edin"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Dil və tərtibatı seçmək üçün tıklayın"</string>
@@ -1710,7 +1710,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Qısayol İstifadə edin"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Rəng İnversiyası"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Rəng korreksiyası"</string>
- <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Bir əlli rejim"</string>
+ <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Birəlli rejim"</string>
<string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Əlavə qaraltma"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Səs səviyyəsi düymələrinə basıb saxlayın. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiv edildi."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Səs səviyyəsi düymələrinə basılaraq saxlanıb. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> deaktiv edilib."</string>
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Admin tərəfindən yeniləndi"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Admin tərəfindən silindi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Enerjiyə Qənaət rejimi Tünd temanı aktivləşdirir, habelə arxa fon fəaliyyətini, bəzi vizual effektləri, müəyyən xüsusiyyətləri və bəzi şəbəkə bağlantılarını məhdudlaşdırır, yaxud söndürür."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Enerjiyə Qənaət rejimi Tünd temanı aktivləşdirir, habelə arxa fon fəaliyyətini, bəzi vizual effektləri, müəyyən xüsusiyyətləri və bəzi şəbəkə bağlantılarını məhdudlaşdırır, yaxud söndürür."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Mobil interneti qənaətlə işlətmək məqsədilə Data Qanaəti bəzi tətbiqlərin fonda data göndərməsinin və qəbulunun qarşısını alır. Hazırda işlətdiyiniz tətbiq nisbətən az müntəzəmliklə data istifadə edə bilər. Örnək olaraq bu, o deməkdir ki, şəkil fayllarına toxunmadıqca onlar açılmayacaq."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Trafikə qənaət edilsin?"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 78a9aa72af8f..31c0bdc84015 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1889,8 +1889,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Potvrdi"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte, određene funkcije i neke mrežne veze."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte, određene funkcije i neke mrežne veze."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Želite da uključite Uštedu podataka?"</string>
@@ -2003,7 +2002,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno nije dostupna. <xliff:g id="APP_NAME_1">%2$s</xliff:g> upravlja dostupnošću."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Opozovi pauziranje aplikacije"</string>
- <string name="work_mode_off_title" msgid="961171256005852058">"Uključiti poslovne aplikacije?"</string>
+ <string name="work_mode_off_title" msgid="961171256005852058">"Uključujete poslovne aplikacije?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Pristupajte poslovnim aplikacijama i obaveštenjima"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
@@ -2126,7 +2125,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Potvrdi"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Poboljšana obaveštenja su zamenila Android prilagodljiva obaveštenja u Android-u 12. Ova funkcija pokazuje predložene radnje i odgovore i organizuje obaveštenja.\n\nPoboljšana obaveštenja mogu da pristupaju sadržaju obaveštenja, uključujući lične podatke poput imena kontakata i poruka. Ova funkcija može i da odbacuje obaveštenja ili da odgovara na njih, na primer, da se javlja na telefonske pozive i kontroliše režim Ne uznemiravaj."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Poboljšana obaveštenja su zamenila Android prilagodljiva obaveštenja u Android-u 12. Ova funkcija pokazuje predložene radnje i odgovore, i organizuje obaveštenja.\n\nPoboljšana obaveštenja mogu da pristupaju sadržaju obaveštenja, uključujući lične podatke poput imena kontakata i poruka. Ova funkcija može i da odbacuje obaveštenja ili da odgovara na njih, na primer, da se javlja na telefonske pozive i kontroliše režim Ne uznemiravaj."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obaveštenje o informacijama Rutinskog režima"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija će se možda isprazniti pre uobičajenog punjenja"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Ušteda baterije je aktivirana da bi se produžilo trajanje baterije"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index fe22c5602902..fcfbc7324c11 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1912,8 +1912,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Абноўлены вашым адміністратарам"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Выдалены вашым адміністратарам"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"У рэжыме эканоміі зараду ўключаецца цёмная тэма і выключаюцца ці абмяжоўваюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты, пэўныя функцыі і падключэнні да сетак."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"У рэжыме эканоміі зараду ўключаецца цёмная тэма і выключаюцца ці абмяжоўваюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты, пэўныя функцыі і падключэнні да сетак."</string>
<string name="data_saver_description" msgid="4995164271550590517">"У рэжыме \"Эканомія трафіка\" фонавая перадача для некаторых праграмам адключана. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але радзей, чым звычайна. Напрыклад, відарысы могуць не загружацца, пакуль вы не націсніце на іх."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Уключыць Эканомію трафіка?"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 6a2db082622a..8c7c9509b1d6 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Актуализирано от администратора ви"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Изтрито от администратора ви"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти, определени функции и някои връзки с мрежата."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти, определени функции и някои връзки с мрежата."</string>
<string name="data_saver_description" msgid="4995164271550590517">"С цел намаляване на преноса на данни функцията за икономия на данни не позволява на някои приложения да изпращат или получават данни на заден план. Понастоящем използвано от вас приложение може да използва данни, но по-рядко. Това например може да означава, че изображенията не се показват, докато не ги докоснете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Включване на „Икономия на данни“?"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 73bf6a5c11ba..3a9d5cb96cf3 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -609,12 +609,10 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"আঙ্গুলের ছাপ আইকন"</string>
- <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
- <skip />
+ <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"\'ফেস আনলক\'"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"আপনার ফেস আবার এনরোল করুন"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"শনাক্তকরণের উন্নতি করতে আপনার ফেস আবার এনরোল করুন"</string>
- <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
- <skip />
+ <string name="face_setup_notification_title" msgid="8843461561970741790">"\'ফেস আনলক\' সেট আপ করুন"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"আপনার ফোনের দিকে তাকিয়ে এটিকে আনলক করুন"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"আনলক করার জন্য বিভিন্ন উপায়ে সেট আপ করুন"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"একটি আঙ্গুলের ছাপ যোগ করতে ট্যাপ করুন"</string>
@@ -641,26 +639,19 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ফেস যাচাই করা যায়নি। হার্ডওয়্যার উপলভ্য নেই।"</string>
- <!-- no translation found for face_error_timeout (2598544068593889762) -->
- <skip />
+ <string name="face_error_timeout" msgid="2598544068593889762">"\'ফেস আনলক\' আবার ব্যবহার করার চেষ্টা করুন"</string>
<string name="face_error_no_space" msgid="5649264057026021723">"নতুন ফেস ডেটা স্টোর করা যায়নি। প্রথমে পুরনোটি মুছে ফেলুন।"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ফেস অপারেশন বাতিল করা হয়েছে৷"</string>
- <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
- <skip />
+ <string name="face_error_user_canceled" msgid="5766472033202928373">"ব্যবহারকারী \'ফেস আনলক\' বাতিল করে দিয়েছেন"</string>
<string name="face_error_lockout" msgid="7864408714994529437">"অনেকবার চেষ্টা করা হয়েছে। পরে আবার চেষ্টা করুন।"</string>
- <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
- <skip />
- <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
- <skip />
+ <string name="face_error_lockout_permanent" msgid="3277134834042995260">"অনেকবার চেষ্টা করেছেন। \'ফেস আনলক\' বন্ধ করা হয়েছে।"</string>
+ <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"অনেকবার চেষ্টা করেছেন। এর পরিবর্তে স্ক্রিন লক ব্যবহার করুন।"</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"আপনার মুখ যাচাই করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
- <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
- <skip />
- <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
- <skip />
+ <string name="face_error_not_enrolled" msgid="1134739108536328412">"এখনও \'ফেস আনলক\' সেট আপ করেননি"</string>
+ <string name="face_error_hw_not_present" msgid="7940978724978763011">"এই ডিভাইসে \'ফেস আনলক\' কাজ করবে না"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> ফেস"</string>
- <!-- no translation found for face_app_setting_name (5854024256907828015) -->
- <skip />
+ <string name="face_app_setting_name" msgid="5854024256907828015">"\'ফেস আনলক\' ব্যবহার করুন"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ফেস অথবা স্ক্রিন লক ব্যবহার করুন"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"চালিয়ে যেতে আপনার মুখ ব্যবহার করুন"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"চালিয়ে যেতে আপনার ফেস বা স্ক্রিন লক ব্যবহার করুন"</string>
@@ -963,8 +954,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"আনলক এলাকা প্রসারিত করুন৷"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"স্লাইড দিয়ে আনলক৷"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"প্যাটার্ন দিয়ে আনলক৷"</string>
- <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
- <skip />
+ <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"\'ফেস আনলক\'।"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"পিন দিয়ে আনলক৷"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"সিম পিন আনলক।"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"সিম পিইউকে আনলক।"</string>
@@ -1876,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপনার প্রশাসক আপডেট করেছেন"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, নির্দিষ্ট ফিচার ও কয়েকটি নেটওয়ার্ক কানেকশনের ব্যবহার সীমিত করে বা বন্ধ করে দেয়।"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, নির্দিষ্ট ফিচার ও কয়েকটি নেটওয়ার্ক কানেকশনের ব্যবহার সীমিত করে বা বন্ধ করে দেয়।"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সেভার চালু করবেন?"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 067d68f993d6..74ba9da3c36b 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1889,7 +1889,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je vaš administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je vaš administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Uredu"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Štednja baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizualne efekte, određene značajke i neke mrežne veze."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije i neke mrežne veze."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Radi smanjenja prijenosa podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. Naprimjer, to može značiti da se slike ne prikazuju dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Uštedu podataka?"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index dddc40be5a90..4099ccbb2f62 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1971,7 +1971,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Més informació"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Reactiva l\'aplicació"</string>
<string name="work_mode_off_title" msgid="961171256005852058">"Activar aplicacions de treball?"</string>
- <string name="work_mode_off_message" msgid="7319580997683623309">"Accedeix a les teves aplicacions de treball i a les notificacions"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"Accedeix a les teves aplicacions i notificacions de treball"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activa"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'aplicació no està disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ara mateix, <xliff:g id="APP_NAME">%1$s</xliff:g> no està disponible."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 8cebc77fa969..c93a26ba07e2 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Opdateret af din administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet af din administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterisparefunktionen aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden og visse visuelle effekter, funktioner og netværksforbindelser."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Batterisparefunktionen aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden og visse visuelle effekter, funktioner og netværksforbindelser."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du aktivere Datasparefunktion?"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4bac1d80319d..a67033fec66e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Von deinem Administrator aktualisiert"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Von deinem Administrator gelöscht"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Der Energiesparmodus aktiviert das dunkle Design und schränkt Hintergrundaktivitäten, einige Funktionen und optische Effekte sowie manche Netzwerkverbindungen ein oder deaktiviert sie."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Der Energiesparmodus aktiviert das dunkle Design und schränkt Hintergrundaktivitäten, einige Funktionen und optische Effekte und manche Netzwerkverbindungen ein oder deaktiviert sie."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Der Datensparmodus verhindert zum einen, dass manche Apps im Hintergrund Daten senden oder empfangen, sodass weniger Daten verbraucht werden. Zum anderen werden die Datenzugriffe der gerade aktiven App eingeschränkt, was z. B. dazu führen kann, dass Bilder erst angetippt werden müssen, bevor sie sichtbar werden."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Datensparmodus aktivieren?"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index a925eea1661e..1b6d3d0dd5bd 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"El modo Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales, ciertas funciones y algunas conexiones de red."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"El modo Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales, ciertas funciones y algunas conexiones de red."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que puede reducir el uso de datos. Una aplicación activa puede acceder a los datos, aunque con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar Ahorro de datos?"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index b315dd8d5781..b2b0226159c9 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administraator on seda värskendanud"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administraator on selle kustutanud"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Akusäästja lülitab sisse tumeda teema ja lülitab välja taustategevused, mõned visuaalsed efektid, teatud funktsioonid ja võrguühendused või piirab neid."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Akusäästja lülitab sisse tumeda teema ja lülitab välja taustategevused, mõned visuaalsed efektid, teatud funktsioonid ja võrguühendused või piirab neid."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Lülitada andmemahu säästja sisse?"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d51884df9e78..d9157831fc2b 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -309,7 +309,7 @@
<string name="permgroupdesc_location" msgid="1995955142118450685">"atzitu gailuaren kokapena"</string>
<string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"atzitu egutegia"</string>
- <string name="permgrouplab_sms" msgid="795737735126084874">"SMS mezuak"</string>
+ <string name="permgrouplab_sms" msgid="795737735126084874">"SMSak"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"bidali eta ikusi SMS mezuak"</string>
<string name="permgrouplab_storage" msgid="1938416135375282333">"Fitxategiak eta multimedia-edukia"</string>
<string name="permgroupdesc_storage" msgid="6351503740613026600">"atzitu gailuko argazkiak, multimedia-edukia eta fitxategiak"</string>
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administratzaileak eguneratu du"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratzaileak ezabatu du"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Ados"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Bateria-aurrezleak gai iluna aktibatzen du, eta murriztu edo desaktibatu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual, eta eginbide jakin eta sareko konexio batzuk."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Bateria-aurrezleak gai iluna aktibatzen du, eta atzeko planoko jarduerak, zenbait efektu bisual, eta eginbide jakin eta sareko konexio batzuk murrizten edo desaktibatzen ditu."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datuen erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Une honetan erabiltzen ari zaren aplikazio batek datuak atzitu ahal izango ditu, baina baliteke maiztasun txikiagoarekin atzitzea. Horrela, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Datu-aurrezlea aktibatu nahi duzu?"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 3f756279081a..f303be0c25bc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم به‌روزرسانی شد"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"توسط سرپرست سیستم حذف شد"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"تأیید"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"«بهینه‌سازی باتری» «طرح زمینه تیره» را روشن می‌کند و فعالیت پس‌زمینه، برخی از جلوه‌های بصری، ویژگی‌هایی خاص، و برخی از اتصال‌های شبکه را محدود یا خاموش می‌کند."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"«بهینه‌سازی باتری» «طرح زمینه تیره» را روشن می‌کند و فعالیت پس‌زمینه، برخی از جلوه‌های بصری، ویژگی‌هایی خاص، و برخی از اتصال‌های شبکه را محدود یا خاموش می‌کند."</string>
<string name="data_saver_description" msgid="4995164271550590517">"برای کمک به کاهش مصرف داده، «صرفه‌جویی داده» از ارسال و دریافت داده در پس‌زمینه در بعضی برنامه‌ها جلوگیری می‌کند. برنامه‌ای که درحال‌حاضر استفاده می‌کنید می‌تواند به داده‌ها دسترسی داشته باشد اما دفعات دسترسی آن محدود است. این می‌تواند به این معنی باشد که، برای مثال، تصاویر تازمانی‌که روی آن‌ها ضربه نزنید نشان داده نمی‌شوند."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"«صرفه‌جویی داده» روشن شود؟"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a9db987f0760..c1c0349817e7 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Järjestelmänvalvoja päivitti tämän."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Järjestelmänvalvoja poisti tämän."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Virransäästö laittaa tumman teeman päälle ja rajoittaa tai laittaa pois päältä taustatoimintoja, tiettyjä ominaisuuksia sekä joitakin visuaalisia tehosteita ja verkkoyhteyksiä."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Virransäästö laittaa tumman teeman päälle ja rajoittaa tai laittaa pois päältä taustatoimintoja, tiettyjä ominaisuuksia sekä joitakin visuaalisia tehosteita ja verkkoyhteyksiä."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Otetaanko Data Saver käyttöön?"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 3412dbc938f3..8abf13370f07 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Mise à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Le mode Économiseur de pile active le thème sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels, certaines fonctionnalités et certaines connexions réseau."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Le mode Économiseur de pile active le thème sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels, certaines fonctionnalités et certaines connexions réseau."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pour aider à diminuer l\'utilisation des données, la fonctionnalité Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données?"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 425e29aed3b6..2660df69d04b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1970,7 +1970,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"L\'application <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas disponible pour le moment. Cette suspension est gérée par l\'application <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"En savoir plus"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Débloquer l\'application"</string>
- <string name="work_mode_off_title" msgid="961171256005852058">"Activer les applis pros ?"</string>
+ <string name="work_mode_off_title" msgid="961171256005852058">"Activer les applis pro ?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Accéder à vos applis et notifications professionnelles"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 54c6a6dd806c..025bc1d53af3 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -712,7 +712,7 @@
<string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Permite ao propietario vincularse á interface de nivel superior dun servizo de mensaxaría. As aplicacións normais non deberían necesitar este permiso."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"vincular aos servizos do operador"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Permite ao titular vincularse aos servizos do operador. As aplicacións normais non deberían necesitar este permiso."</string>
- <string name="permlab_access_notification_policy" msgid="5524112842876975537">"acceso ao modo Non molestar"</string>
+ <string name="permlab_access_notification_policy" msgid="5524112842876975537">"acceso a Non molestar"</string>
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permite á aplicación ler e escribir a configuración do modo Non molestar."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"iniciar uso de permiso de vista"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite ao propietario iniciar o uso de permisos dunha aplicación. As aplicacións normais non deberían precisalo nunca."</string>
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado polo teu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado polo teu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Coa función Aforro de batería, actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e determinadas funcións e conexións de rede."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Coa función Aforro de batería, actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e determinadas funcións e conexións de rede."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para contribuír a reducir o uso de datos, o aforro de datos impide que algunhas aplicacións envíen ou reciban datos en segundo plano. Cando esteas utilizando unha aplicación, esta poderá acceder aos datos, pero é posible que o faga con menos frecuencia. Por exemplo, poida que as imaxes non se mostren ata que as toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Queres activar o aforro de datos?"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 6db75a0fab96..0e9d5d5679b5 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ઓકે"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ, અમુક સુવિધાઓ અને કેટલાક નેટવર્ક કનેક્શન મર્યાદિત કે બંધ કરે છે."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ, અમુક સુવિધાઓ અને કેટલાક નેટવર્ક કનેક્શન મર્યાદિત કે બંધ કરે છે."</string>
<string name="data_saver_description" msgid="4995164271550590517">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપને બૅકગ્રાઉન્ડમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેમને ટૅપ નહીં કરો."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ડેટા સેવર ચાલુ કરીએ?"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b30fd3096540..d686450a6f3c 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपके व्यवस्थापक ने अपडेट किया है"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपके व्यवस्थापक ने हटा दिया है"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, यह बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, कुछ खास सुविधाओं, और कुछ खास तरह के इंटरनेट कनेक्शन इस्तेमाल करने से डिवाइस को रोकता है या इन्हें बंद कर देता है."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, यह बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, कुछ खास सुविधाओं, और कुछ खास तरह के इंटरनेट कनेक्शन इस्तेमाल करने से डिवाइस को रोकता है या इन्हें बंद कर देता है."</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटा खर्च को कम करने के लिए, डेटा बचाने की सेटिंग कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकती है. फ़िलहाल, आप जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा ऐक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी, जब तक आप उन पर टैप नहीं करते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा बचाने की सेटिंग चालू करें?"</string>
@@ -2093,7 +2092,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"चालू करें"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"बंद करें"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ज़्यादा जानें"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 में, ज़रूरत के हिसाब से सूचनाएं पाने की सुविधा की जगह अब \'बेहतर सूचनाएं\' सुविधा काम करेगी. यह सुविधा आपको कार्रवाइयों और जवाबों के सुझाव दिखाती है. साथ ही, आपके डिवाइस पर मिलने वाली सूचनाओं को व्यवस्थित करती है.\n\n\'बेहतर सूचनाएं\' सुविधा, डिवाइस पर मिलने वाली सभी सूचनाओं का कॉन्टेंट ऐक्सेस कर सकती है. इसमें आपकी निजी जानकारी, जैसे कि संपर्कों के नाम और मैसेज शामिल हैं. यह सुविधा, सूचनाओं को रद्द कर सकती है या उनका जवाब भी दे सकती है, जैसे कि फ़ोन कॉल का जवाब देना और \'परेशान न करें\' को कंट्रोल करना."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 में, ज़रूरत के हिसाब से सूचनाएं पाने की सुविधा की जगह अब \'बेहतर सूचनाएं\' सुविधा काम करेगी. यह सुविधा आपको कार्रवाइयों और जवाबों के सुझाव दिखाती है. साथ ही, आपके डिवाइस पर मिलने वाली सूचनाओं को व्यवस्थित करती है.\n\n\'बेहतर सूचनाएं\' सुविधा, डिवाइस पर मिलने वाली सभी सूचनाओं का कॉन्टेंट ऐक्सेस कर सकती है. इसमें आपकी निजी जानकारी, जैसे कि संपर्कों के नाम और मैसेज शामिल हैं. यह सुविधा, सूचनाओं को खारिज कर सकती है या उनका जवाब भी दे सकती है, जैसे कि फ़ोन कॉल का जवाब देना और \'परेशान न करें\' को कंट्रोल करना."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"रूटीन मोड जानकारी की सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"बैटरी आम तौर पर जितने समय चलती है, उससे पहले खत्म हो सकती है"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"बैटरी लाइफ़ बढ़ाने के लिए \'बैटरी सेवर\' चालू हो गया है"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 108ce3354245..3d15380196f3 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"A rendszergazda által frissítve"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"A rendszergazda által törölve"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, és korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, valamint bizonyos vizuális effekteket, funkciókat és hálózati kapcsolatokat."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, és korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, valamint bizonyos vizuális effekteket, funkciókat és hálózati kapcsolatokat."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Az adatforgalom csökkentése érdekében az Adatforgalom-csökkentő megakadályozza, hogy egyes alkalmazások adatokat küldjenek vagy fogadjanak a háttérben. Az Ön által jelenleg használt alkalmazások hozzáférhetnek az adatokhoz, de csak ritkábban. Ez például azt jelentheti, hogy a képek csak rákoppintás után jelennek meg."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Bekapcsolja az Adatforgalom-csökkentőt?"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 863948fbacd3..9b4bb13cc972 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ, ցանցային միացումներ և այլ գործառույթներ։"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ, ցանցային միացումներ և այլ գործառույթներ։"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Թրաֆիկի տնտեսման ռեժիմում որոշ հավելվածների համար տվյալների ֆոնային փոխանցումն անջատված է։ Հավելվածը, որն օգտագործում եք, կարող է տվյալներ փոխանցել և ստանալ, սակայն ոչ այնքան հաճախ: Օրինակ՝ պատկերները կցուցադրվեն միայն դրանց վրա սեղմելուց հետո։"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Միացնե՞լ թրաֆիկի տնտեսումը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 489d3ccd83c6..7dbf5664f59d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Diupdate oleh admin Anda"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dihapus oleh admin Anda"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Oke"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Penghemat Baterai akan mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas latar belakang, beberapa efek visual, fitur tertentu, dan beberapa koneksi jaringan."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Penghemat Baterai akan mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas latar belakang, beberapa efek visual, fitur tertentu, dan beberapa koneksi jaringan."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu mengurangi penggunaan data, Penghemat Data mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah diketuk."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Aktifkan Penghemat Data?"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index abc91388fd4e..a15275bc737b 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -815,7 +815,7 @@
<string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"Sérsniðið"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"Afmæli"</string>
- <string name="eventTypeAnniversary" msgid="4684702412407916888">"Brúðkaupsafmæli"</string>
+ <string name="eventTypeAnniversary" msgid="4684702412407916888">"Afmæli"</string>
<string name="eventTypeOther" msgid="530671238533887997">"Annað"</string>
<string name="emailTypeCustom" msgid="1809435350482181786">"Sérsniðið"</string>
<string name="emailTypeHome" msgid="1597116303154775999">"Heima"</string>
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Kerfisstjóri uppfærði"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Kerfisstjóri eyddi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Í lagi"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Rafhlöðusparnaður kveikir á dökku þema og takmarkar eða slekkur á bakgrunnsvirkni, sumum myndáhrifum, tilteknum eiginleikum og sumum nettengingum."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Rafhlöðusparnaður kveikir á dökku þema og takmarkar eða slekkur á bakgrunnsvirkni, sumum áhrifum, tilteknum eiginleikum og sumum nettengingum."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Gagnasparnaður getur hjálpað til við að draga úr gagnanotkun með því að hindra forrit í að senda eða sækja gögn í bakgrunni. Forrit sem er í notkun getur náð í gögn, en gerir það kannski sjaldnar. Niðurstaðan getur verið að myndir eru ekki birtar fyrr en þú ýtir á þær, svo dæmi sé tekið."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Kveikja á gagnasparnaði?"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 12ee90ee3f09..3191bd635f83 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"L\'opzione Risparmio energetico attiva il tema scuro e limita o disattiva l\'attività in background, nonché alcuni effetti visivi, funzionalità e connessioni di rete."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"L\'opzione Risparmio energetico attiva il tema scuro e limita o disattiva l\'attività in background, nonché alcuni effetti visivi, funzionalità e connessioni di rete."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 0a3ef050db77..1ff6e9dcb9a0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -865,7 +865,7 @@
<string name="relationTypeSister" msgid="3721676005094140671">"אחות"</string>
<string name="relationTypeSpouse" msgid="6916682664436031703">"בן/בת זוג"</string>
<string name="sipAddressTypeCustom" msgid="6283889809842649336">"בהתאמה אישית"</string>
- <string name="sipAddressTypeHome" msgid="5918441930656878367">"דף הבית"</string>
+ <string name="sipAddressTypeHome" msgid="5918441930656878367">"בית"</string>
<string name="sipAddressTypeWork" msgid="7873967986701216770">"עבודה"</string>
<string name="sipAddressTypeOther" msgid="6317012577345187275">"אחר"</string>
<string name="quick_contacts_not_available" msgid="1262709196045052223">"לא נמצאה אפליקציה להצגת התוכן הזה."</string>
@@ -1912,8 +1912,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"עודכנה על ידי מנהל המערכת"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"נמחקה על ידי מנהל המערכת"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"אישור"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה פעילות ברקע, חלק מהאפקטים החזותיים, תכונות מסוימות וחלק מהחיבורים לרשתות."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה פעילות ברקע, חלק מהאפקטים החזותיים, תכונות מסוימות וחלק מהחיבורים לרשתות."</string>
<string name="data_saver_description" msgid="4995164271550590517">"‏כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות לשלוח או לקבל נתונים ברקע. אפליקציות שבהן נעשה שימוש כרגע יכולות לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"להפעיל את חוסך הנתונים?"</string>
@@ -2036,7 +2035,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"מידע נוסף"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ביטול ההשהיה של האפליקציה"</string>
<string name="work_mode_off_title" msgid="961171256005852058">"להפעיל את האפליקציות לעבודה?"</string>
- <string name="work_mode_off_message" msgid="7319580997683623309">"קבלת גישה להתראות ולאפליקציות לעבודה"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"קבלת גישה להתראות ולאפליקציות בפרופיל העבודה"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"הפעלה"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"האפליקציה לא זמינה"</string>
<string name="app_blocked_message" msgid="542972921087873023">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא זמינה בשלב זה."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 9f446558c619..d98974fcc7c9 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"管理者により更新されています"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"管理者により削除されています"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"バッテリー セーバーを有効にすると、ダークテーマが ON になり、バックグラウンド アクティビティ、一部の視覚効果、特定の機能、一部のネットワーク接続が制限されるか OFF になります。"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"バッテリー セーバーを有効にすると、ダークテーマが ON になり、バックグラウンド アクティビティ、一部の視覚効果、特定の機能、一部のネットワーク接続が制限されるか OFF になります。"</string>
<string name="data_saver_description" msgid="4995164271550590517">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータを送受信することはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"データセーバーを ON にしますか?"</string>
@@ -1972,7 +1971,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"詳細"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"アプリの一時停止を解除"</string>
<string name="work_mode_off_title" msgid="961171256005852058">"仕事用アプリを ON にしますか?"</string>
- <string name="work_mode_off_message" msgid="7319580997683623309">"仕事用のアプリや通知を利用する"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"仕事用のアプリを利用し、通知を受け取れるようになります"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ON にする"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"アプリの利用不可"</string>
<string name="app_blocked_message" msgid="542972921087873023">"現在 <xliff:g id="APP_NAME">%1$s</xliff:g> はご利用になれません。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index af21c1169b31..1d5661b6fe95 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"წაიშალა თქვენი ადმინისტრატორის მიერ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"კარგი"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტს, გარკვეულ ფუნქციებსა და ზოგიერთ ქსელთან კავშირს."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტს, გარკვეულ ფუნქციებსა და ზოგიერთ ქსელთან კავშირს."</string>
<string name="data_saver_description" msgid="4995164271550590517">"მობილური ინტერნეტის მოხმარების შემცირების მიზნით, მონაცემთა დამზოგველი ზოგიერთ აპს ფონურ რეჟიმში მონაცემთა გაგზავნასა და მიღებას შეუზღუდავს. თქვენ მიერ ამჟამად გამოყენებული აპი მაინც შეძლებს მობილურ ინტერნეტზე წვდომას, თუმცა ამას ნაკლები სიხშირით განახორციელებს. ეს ნიშნავს, რომ, მაგალითად, სურათები არ გამოჩნდება მანამ, სანამ მათ საგანგებოდ არ შეეხებით."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ჩაირთოს მონაცემთა დამზოგველი?"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 6d24f8f21462..9e72ec87dac5 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1473,7 +1473,7 @@
<string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Бұл өтініштің орындалуын қалайсыз ба?"</string>
<string name="grant_permissions_header_text" msgid="3420736827804657201">"Кіру өтініші"</string>
<string name="allow" msgid="6195617008611933762">"Рұқсат беру"</string>
- <string name="deny" msgid="6632259981847676572">"Бас тарту"</string>
+ <string name="deny" msgid="6632259981847676572">"Тыйым салу"</string>
<string name="permission_request_notification_title" msgid="1810025922441048273">"Рұқсат өтінілді"</string>
<string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Рұқсат \nесептік жазба үшін <xliff:g id="ACCOUNT">%s</xliff:g> өтінілді."</string>
<string name="forward_intent_to_owner" msgid="4620359037192871015">"Осы қолданбаны жұмыс профиліңізден тыс пайдаланып жатырсыз"</string>
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Әкімші жаңартқан"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Әкімші жойған"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Жарайды"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлерге, белгілі бір функциялар мен кейбір желі байланыстарына шектеу қояды немесе оларды өшіреді."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлерге, белгілі бір функциялар мен кейбір желі байланыстарына шектеу қояды немесе оларды өшіреді."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Дерек шығынын азайту үшін Трафикті үнемдеу режимінде кейбір қолданбаларға деректі фондық режимде жіберуге және алуға тыйым салынады. Ашық тұрған қолданба деректі шектеулі шамада пайдаланады (мысалы, кескіндер оларды түрткенге дейін көрсетілмейді)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Трафикті үнемдеу режимі қосылсын ба?"</string>
@@ -1972,7 +1971,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Толығырақ"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Қолданбаны қайта қосу"</string>
<string name="work_mode_off_title" msgid="961171256005852058">"Жұмыс қолданбаларын қосасыз ба?"</string>
- <string name="work_mode_off_message" msgid="7319580997683623309">"Жұмыс қолданбалары мен хабарландыруларына рұқсат алу"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"Жұмыс қолданбалары мен хабарландыруларына қол жеткізесіз."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Қосу"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 3a4117d69912..1389104abe3a 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ធ្វើ​បច្ចុប្បន្នភាព​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"លុប​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"យល់ព្រម"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"មុខងារ​សន្សំថ្មបើករចនាប័ទ្មងងឹត និងដាក់កំហិត ឬបិទសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន មុខងារជាក់លាក់ និងការតភ្ជាប់បណ្ដាញមួយចំនួន។"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"មុខងារ​សន្សំថ្មបើករចនាប័ទ្មងងឹត និងដាក់កំហិត ឬបិទសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន មុខងារជាក់លាក់ និងការតភ្ជាប់បណ្ដាញមួយចំនួន។"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់​ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យ?"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 9a39c298d9e1..470683d06134 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್‌ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ಸರಿ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ಬ್ಯಾಟರಿ ಸೇವರ್, ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು, ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಮತ್ತು ಇತರ ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು, ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಮತ್ತು ಇತರ ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
<string name="data_saver_description" msgid="4995164271550590517">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ಡೇಟಾ ಸೇವರ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 86d49cd4598f..5474a493c609 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"관리자에 의해 업데이트되었습니다."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"관리자에 의해 삭제되었습니다."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"확인"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"절전 기능은 어두운 테마를 사용 설정하고 백그라운드 활동, 일부 시각 효과, 특정 기능 및 일부 네트워크 연결을 제한하거나 사용 중지합니다."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"절전 기능은 어두운 테마를 사용 설정하고 백그라운드 활동, 일부 시각 효과, 특정 기능 및 일부 네트워크 연결을 제한하거나 사용 중지합니다."</string>
<string name="data_saver_description" msgid="4995164271550590517">"데이터 사용량을 줄이기 위해 데이터 절약 모드는 일부 앱이 백그라운드에서 데이터를 전송하거나 수신하지 못하도록 합니다. 현재 사용 중인 앱에서 데이터에 액세스할 수 있지만 빈도가 줄어듭니다. 예를 들면, 이미지를 탭하기 전에는 이미지가 표시되지 않습니다."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"데이터 절약 모드를 사용 설정하시겠습니까?"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 67c8bb7fb266..984e6f6a2166 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Администраторуңуз жаңыртып койгон"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Администраторуңуз жок кылып салган"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ЖАРАЙТ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батареяны үнөмдөгүч режиминде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер, белгилүү бир функциялар жана айрым тармакка туташуулар чектелип же өчүрүлөт."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Батареяны үнөмдөгүч режиминде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер, белгилүү бир функциялар жана айрым тармакка туташуулар чектелип же өчүрүлөт."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Трафикти үнөмдөө режиминде айрым колдонмолор маалыматтарды фондо өткөрө алышпайт. Учурда сиз пайдаланып жаткан колдонмо маалыматтарды жөнөтүп/ала алат, бирок адаттагыдан азыраак өткөргөндүктөн, анын айрым функциялары талаптагыдай иштебей коюшу мүмкүн. Мисалы, сүрөттөр басылмайынча жүктөлбөйт."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Трафикти үнөмдөө режимин иштетесизби?"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 1ff849cb80eb..5de05faffdf3 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ຖືກອັບໂຫລດໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ຖືກລຶບອອກໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ຕົກລົງ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບຈຳນວນໜຶ່ງ, ຄຸນສົມບັດບາງຢ່າງ ແລະ ການເຊື່ອມຕໍ່ເຄືອຂ່າຍບາງອັນ."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບຈຳນວນໜຶ່ງ, ຄຸນສົມບັດບາງຢ່າງ ແລະ ການເຊື່ອມຕໍ່ເຄືອຂ່າຍບາງອັນ."</string>
<string name="data_saver_description" msgid="4995164271550590517">"ເພື່ອຊ່ວຍຫຼຸດຜ່ອນການນຳໃຊ້ຂໍ້ມູນ, ຕົວປະຢັດອິນເຕີເນັດຈະປ້ອງກັນບໍ່ໃຫ້ບາງແອັບສົ່ງ ຫຼື ຮັບຂໍ້ມູນໃນພື້ນຫຼັງ. ແອັບໃດໜຶ່ງທີ່ທ່ານກຳລັງໃຊ້ຢູ່ຈະສາມາດເຂົ້າເຖິງຂໍ້ມູນໄດ້ ແຕ່ອາດເຂົ້າເຖິງໄດ້ຖີ່ໜ້ອຍລົງ. ນີ້ອາດໝາຍຄວາມວ່າ ຮູບພາບຕ່າງໆອາດບໍ່ສະແດງຈົນກວ່າທ່ານຈະແຕະໃສ່ກ່ອນ."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ເປີດຕົວປະຢັດອິນເຕີເນັດບໍ?"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 56e89d0e8219..b7d4e0883897 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1889,8 +1889,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atjaunināja administrators"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dzēsa administrators"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Labi"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs un tiek ierobežotas vai izslēgtas darbības fonā, daži vizuālie efekti, noteiktas funkcijas un noteikti tīkla savienojumi."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs un tiek ierobežotas vai izslēgtas darbības fonā, daži vizuālie efekti, noteiktas funkcijas un noteikti tīkla savienojumi."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vai ieslēgt datu lietojuma samazinātāju?"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 674ef1610eec..6c9f99d029f6 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирано од администраторот"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Избришано од администраторот"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Во ред"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"„Штедачот на батерија“ вклучува темна тема и ја ограничува или исклучува активноста во заднина, некои визуелни ефекти, одредени функции и некои мрежни врски."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"„Штедачот на батерија“ вклучува темна тема и ја ограничува или исклучува активноста во заднина, некои визуелни ефекти, одредени функции и некои мрежни врски."</string>
<string name="data_saver_description" msgid="4995164271550590517">"За да се намали користењето интернет, „Штедачот на интернет“ спречува дел од апликациите да испраќаат или да примаат податоци во заднина. Одредена апликација што ја користите ќе може да користи интернет, но можеби тоа ќе го прави поретко. Ова значи, на пример, дека сликите нема да се прикажуваат додека не ги допрете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Да се вклучи „Штедач на интернет“?"</string>
@@ -2089,11 +2088,11 @@
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Известувањево е рангирано повисоко. Допрете за да дадете повратни информации."</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"Известувањево е рангирано пониско. Допрете за да дадете повратни информации."</string>
<string name="nas_upgrade_notification_title" msgid="8436359459300146555">"Подобрени известувања"</string>
- <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"„Подобрените известувања“ сега ги даваат предложените дејства и одговорите. „Приспособливите известувања на Android“ веќе не се достапни."</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"„Подобрените известувања“ сега ги даваат предложените дејства и одговорите. „Адаптивните известувања на Android“ веќе не се достапни."</string>
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Во ред"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Исклучи"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Дознајте повеќе"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"„Подобрените известувања“ ги заменија „Приспособливите известувања на Android“ во Android 12. Оваа функција прикажува предложени дејства и одговори и ги организира вашите известувања.\n\n„Подобрените известувања“ може да пристапат до содржините од известувањата, вклучително и личните податоци, како што се имињата на контактите и пораките. Функцијава може и да отфрла или одговара на известувања, како на пример, одговарање телефонски повици и да ја контролира „Не вознемирувај“."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"„Подобрените известувања“ ги заменија „Адаптивните известувања на Android“ во Android 12. Оваа функција прикажува предложени дејства и одговори и ги организира вашите известувања. \n\n„Подобрените известувања“ може да пристапуваат до содржините од известувањата, вклучително и личните податоци, како што се имињата на контактите и пораките. Функцијава може и да ги отфрла или да одговара на известувањата, како на пример, да одговара на телефонски повици и да го контролира режимот „Не вознемирувај“."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Известување за информации за режимот за рутини"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батеријата може да се потроши пред вообичаеното време за полнење"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Активиран е „Штедачот на батерија“ за да се продолжи траењето на батеријата"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 7d1bb9b97757..f468ab008ae2 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -315,7 +315,7 @@
<string name="permgroupdesc_storage" msgid="6351503740613026600">"നിങ്ങളുടെ ഉപകരണത്തിലെ ഫോട്ടോകളും മീഡിയയും ഫയലുകളും ആക്സസ് ചെയ്യുക"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"മൈക്രോഫോണ്‍"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"ഓഡിയോ റെക്കോർഡ് ചെയ്യുക"</string>
- <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"കായിക പ്രവർത്തനം"</string>
+ <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"ശാരീരിക ആക്റ്റിവിറ്റി"</string>
<string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"ശാരീരിക പ്രവർത്തനം ആക്‌സസ് ചെയ്യുക"</string>
<string name="permgrouplab_camera" msgid="9090413408963547706">"ക്യാമറ"</string>
<string name="permgroupdesc_camera" msgid="7585150538459320326">"ചിത്രങ്ങളെടുത്ത് വീഡിയോ റെക്കോർഡുചെയ്യുക"</string>
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"നിങ്ങളുടെ അഡ്‌മിൻ അപ്‌ഡേറ്റ് ചെയ്യുന്നത്"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"നിങ്ങളുടെ അഡ്‌മിൻ ഇല്ലാതാക്കുന്നത്"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ശരി"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"\'ബാറ്ററി ലാഭിക്കൽ\' ഡാർക്ക് തീം ഓണാക്കുന്നു, ഒപ്പം പശ്ചാത്തല ആക്‌റ്റിവിറ്റിയും ചില വിഷ്വൽ ഇഫക്റ്റുകളും ചില ഫീച്ചറുകളും ചില നെറ്റ്‌വർക്ക് കണക്ഷനുകളും പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"ബാറ്ററി ലാഭിക്കൽ ഡാർക്ക് തീം ഓണാക്കുന്നു, പശ്ചാത്തല ആക്‌റ്റിവിറ്റിയും ചില വിഷ്വൽ ഇഫക്റ്റുകളും ചില ഫീച്ചറുകളും ചില നെറ്റ്‌വർക്ക് കണക്ഷനുകളും അത് പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
<string name="data_saver_description" msgid="4995164271550590517">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിനായി പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്പുകളെ ഡാറ്റാ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്‌സസ് ചെയ്യാനാകും, എന്നാൽ വല്ലപ്പോഴും മാത്രമെ സംഭവിക്കുന്നുള്ളു. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദ‍‍‍ർശിപ്പിക്കുകയില്ല എന്നാണ്."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 4f87dd60e6e7..36165362a2d4 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Таны админ шинэчилсэн"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Таны админ устгасан"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект, тодорхой онцлогууд болон зарим сүлжээний холболтыг хязгаарлах эсвэл унтраана."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект, тодорхой онцлогууд болон зарим сүлжээний холболтыг хязгаарлах эсвэл унтраана."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Дата ашиглалтыг багасгахын тулд дата хэмнэгч нь ар талд ажиллаж буй зарим апп-н өгөгдлийг илгээх болон авахаас сэргийлдэг. Таны одоогийн ашиглаж буй апп нь өгөгдөлд хандах боломжтой хэдий ч тогтмол хандахгүй. Энэ нь жишээлбэл зургийг товших хүртэл харагдахгүй гэсэн үг юм."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Дата хэмнэгчийг асаах уу?"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index e4901291f518..69e3c74ea601 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपल्या प्रशासकाने अपडेट केले"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपल्या प्रशासकाने हटवले"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ओके"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट, ठरावीक वैशिष्ट्ये व काही नेटवर्क कनेक्शन मर्यादित किंवा बंद करते."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट, ठरावीक वैशिष्ट्ये व काही नेटवर्क कनेक्शन मर्यादित किंवा बंद करते."</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अ‍ॅप्सना बॅकग्राउंडमध्ये डेटा पाठवण्यास किंवा मिळवण्यास डेटा सर्व्हर प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अ‍ॅप डेटा अ‍ॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असे होऊ शकते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेव्हर सुरू करायचे?"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 2f90b58439e4..23fc7bbb4c9d 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့၊ ဝန်ဆောင်မှုအချို့နှင့် ကွန်ရက်ချိတ်ဆက်မှုအချို့တို့ကို ကန့်သတ်သည် သို့မဟုတ် ပိတ်သည်။"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့၊ ဝန်ဆောင်မှုအချို့နှင့် ကွန်ရက်ချိတ်ဆက်မှုအချို့တို့ကို ကန့်သတ်သည် သို့မဟုတ် ပိတ်သည်။"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ဒေတာအသုံးလျှော့ချနိုင်ရန်အတွက် အက်ပ်များကို နောက်ခံတွင် ဒေတာပို့ခြင်းနှင့် လက်ခံခြင်းမပြုရန် \'ဒေတာချွေတာမှု\' စနစ်က တားဆီးထားပါသည်။ ယခုအက်ပ်ဖြင့် ဒေတာအသုံးပြုနိုင်သော်လည်း အကြိမ်လျှော့၍သုံးရပါမည်။ ဥပမာ၊ သင်က မတို့မချင်း ပုံများပေါ်လာမည် မဟုတ်ပါ။"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ဒေတာချွေတာမှုစနစ် ဖွင့်မလား။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 5228c6a862b3..d24c87933ec4 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -187,7 +187,7 @@
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Av en ukjent tredjepart"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Av administratoren for jobbprofilen din"</string>
<string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Av <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
- <string name="work_profile_deleted" msgid="5891181538182009328">"Arbeidsprofilen er slettet"</string>
+ <string name="work_profile_deleted" msgid="5891181538182009328">"Jobbprofilen er slettet"</string>
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Administratorappen for jobbprofilen mangler eller er skadet. Dette har ført til at jobbprofilen og alle data knyttet til den, har blitt slettet. Ta kontakt med administratoren for å få hjelp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jobbprofilen din er ikke lenger tilgjengelig på denne enheten"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"For mange passordforsøk"</string>
@@ -1476,7 +1476,7 @@
<string name="deny" msgid="6632259981847676572">"Avslå"</string>
<string name="permission_request_notification_title" msgid="1810025922441048273">"Tillatelse forespurt"</string>
<string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Tillatelse forespurt\nfor kontoen <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
- <string name="forward_intent_to_owner" msgid="4620359037192871015">"Du bruker denne appen utenfor arbeidsprofilen"</string>
+ <string name="forward_intent_to_owner" msgid="4620359037192871015">"Du bruker denne appen utenfor jobbprofilen"</string>
<string name="forward_intent_to_work" msgid="3620262405636021151">"Du bruker denne appen i jobbprofilen din"</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"Inndatametode"</string>
<string name="sync_binding_label" msgid="469249309424662147">"Synkronisering"</string>
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Oppdatert av administratoren din"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet av administratoren din"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter, noen funksjoner og noen nettverkstilkoblinger."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter, noen funksjoner og noen nettverkstilkoblinger."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datasparing hindrer noen apper fra å sende og motta data i bakgrunnen, for å redusere dataforbruket. Aktive apper kan bruke data, men kanskje ikke så mye som ellers – for eksempel vises ikke bilder før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du slå på Datasparing?"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index ca8d403da1e7..13a17366f0e4 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1198,7 +1198,7 @@
<string name="whichSendToApplication" msgid="77101541959464018">"यसको प्रयोग गरी पठाउनुहोस्"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"%1$s को प्रयोग गरी पठाउनुहोस्"</string>
<string name="whichSendToApplicationLabel" msgid="3543240188816513303">"पठाउनुहोस्"</string>
- <string name="whichHomeApplication" msgid="8276350727038396616">"गृह एप चयन गर्नुहोस्"</string>
+ <string name="whichHomeApplication" msgid="8276350727038396616">"होम एप चयन गर्नुहोस्"</string>
<string name="whichHomeApplicationNamed" msgid="5855990024847433794">"%1$s लाई गृहको रूपमा प्रयोग गर्नुहोस्"</string>
<string name="whichHomeApplicationLabel" msgid="8907334282202933959">"छविलाई कैंद गर्नुहोस्"</string>
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"यस मार्फत छविलाई कैंद गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 0c9a278b5b50..4dc2a1b6d3b2 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1367,7 +1367,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Analoog audioaccessoire gedetecteerd"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Het aangesloten apparaat werkt niet met deze telefoon. Tik voor meer informatie."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"USB-foutopsporing verbonden"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Tik om USB-foutopsporing uit te zetten."</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Tik om USB-foutopsporing uit te zetten"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecteer deze optie om USB-foutopsporing uit te zetten."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Draadloze foutopsporing verbonden"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tik om draadloze foutopsporing uit te zetten"</string>
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Geüpdatet door je beheerder"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Verwijderd door je beheerder"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, bepaalde visuele effecten, bepaalde functies en sommige netwerkverbindingen beperkt of uitgezet."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, bepaalde visuele effecten, bepaalde functies en sommige netwerkverbindingen beperkt of uitgezet."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens sturen of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Databesparing aanzetten?"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 5584324d6043..d12bb0b06b43 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଅପଡେଟ୍‍ କରିଛନ୍ତି"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଡିଲିଟ୍‍ କରିଛନ୍ତି"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ଠିକ୍ ଅଛି"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ବ୍ୟାଟେରୀ ସେଭର୍ ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ଇଫେକ୍ଟ, କିଛି ଫିଚର୍ ଏବଂ କିଛି ନେଟୱାର୍କ ସଂଯୋଗକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"ବ୍ୟାଟେରୀ ସେଭର୍ ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ଇଫେକ୍ଟ, କିଛି ଫିଚର୍ ଏବଂ କିଛି ନେଟୱାର୍କ ସଂଯୋଗକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ଡାଟା ବ୍ୟବହାର କମ୍‍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଡାଟା ସେଭର୍‍ ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡରେ ଡାଟା ପଠାଇବା କିମ୍ବା ପ୍ରାପ୍ତ କରିବାକୁ କିଛି ଆପ୍‍କୁ ବାରଣ କରେ। ଆପଣ ବର୍ତ୍ତମାନ ବ୍ୟବହାର କରୁଥିବା ଆପ୍‍, ଡାଟା ଆକ୍ସେସ୍‍ କରିପାରେ, କିନ୍ତୁ ଏହା କମ୍‍ ଥର କରିପାରେ। ଏହାର ଅର୍ଥ ହୋଇପାରେ ଯେମିତି ଆପଣ ଇମେଜଗୁଡ଼ିକୁ ଟାପ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ସେଗୁଡ଼ିକ ଡିସପ୍ଲେ ହୁଏ ନାହିଁ।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ଡାଟା ସେଭର୍‌ ଚାଲୁ କରିବେ?"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 564fb19b88a0..89eb90c8788b 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1252,7 +1252,7 @@
<string name="noApplications" msgid="1186909265235544019">"Żadna z aplikacji nie może wykonać tej czynności."</string>
<string name="aerr_application" msgid="4090916809370389109">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> przestała działać"</string>
<string name="aerr_process" msgid="4268018696970966407">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> przestał działać"</string>
- <string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> wciąż przestaje działać"</string>
+ <string name="aerr_application_repeated" msgid="7804378743218496566">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> wciąż przestaje działać"</string>
<string name="aerr_process_repeated" msgid="1153152413537954974">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> wciąż przestaje działać"</string>
<string name="aerr_restart" msgid="2789618625210505419">"Otwórz aplikację ponownie"</string>
<string name="aerr_report" msgid="3095644466849299308">"Prześlij opinię"</string>
@@ -1912,8 +1912,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Zaktualizowany przez administratora"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Usunięty przez administratora"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne, pewne funkcje oraz wybrane połączenia sieciowe."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne, pewne funkcje oraz wybrane połączenia sieciowe."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Włączyć Oszczędzanie danych?"</string>
@@ -2036,7 +2035,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Więcej informacji"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Wznów działanie aplikacji"</string>
<string name="work_mode_off_title" msgid="961171256005852058">"Włączyć aplikacje służbowe?"</string>
- <string name="work_mode_off_message" msgid="7319580997683623309">"Uzyskaj dostęp do aplikacji służbowych i powiadomień"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"Uzyskaj dostęp do służbowych aplikacji i powiadomień"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Włącz"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacja jest niedostępna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest obecnie niedostępna."</string>
@@ -2159,7 +2158,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Wyłącz"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Więcej informacji"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"W Androidzie 12 ulepszone powiadomienia zastąpiły powiadomienia adaptacyjne. Ta funkcja pokazuje sugerowane działania i odpowiedzi oraz porządkuje powiadomienia.\n\nUlepszone powiadomienia mogą czytać wszystkie powiadomienia, w tym dane osobowe takie jak nazwy kontaktów i treść wiadomości. Funkcja może też zamykać powiadomienia oraz reagować na nie, np. odbierać połączenia telefoniczne i sterować trybem Nie przeszkadzać."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"W Androidzie 12 ulepszone powiadomienia zastąpiły dotychczasowe powiadomienia adaptacyjne. Ta funkcja pokazuje sugerowane działania i odpowiedzi oraz porządkuje powiadomienia.\n\nUlepszone powiadomienia mogą czytać całą zawartość powiadomień, w tym dane osobowe takie jak nazwy kontaktów i treść wiadomości. Funkcja może też zamykać powiadomienia oraz reagować na nie, np. odbierać połączenia telefoniczne i sterować trybem Nie przeszkadzać."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Powiadomienie z informacją o trybie rutynowym"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria może się wyczerpać przed zwykłą porą ładowania"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Włączono Oszczędzanie baterii, by wydłużyć czas pracy na baterii"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c5cb90cbc581..953eb72e9c76 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1889,8 +1889,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizat de administratorul dvs."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Șters de administratorul dvs."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Economisirea bateriei activează tema întunecată și restricționează sau dezactivează activitatea în fundal, unele efecte vizuale, alte funcții și câteva conexiuni la rețea."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Economisirea bateriei activează tema întunecată și restricționează sau dezactivează activitatea în fundal, unele efecte vizuale, alte funcții și câteva conexiuni la rețea."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pentru a contribui la reducerea utilizării de date, Economizorul de date împiedică unele aplicații să trimită sau să primească date în fundal. O aplicație pe care o folosiți poate accesa datele, însă mai rar. Aceasta poate însemna, de exemplu, că imaginile se afișează numai după ce le atingeți."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activați Economizorul de date?"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index fe86339665d3..4adc5a95ff8b 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -331,7 +331,7 @@
<string name="permgroupdesc_calllog" msgid="2026996642917801803">"чтение и запись телефонных звонков"</string>
<string name="permgrouplab_phone" msgid="570318944091926620">"Телефон"</string>
<string name="permgroupdesc_phone" msgid="270048070781478204">"осуществлять вызовы и управлять ими"</string>
- <string name="permgrouplab_sensors" msgid="9134046949784064495">"Датчики на теле"</string>
+ <string name="permgrouplab_sensors" msgid="9134046949784064495">"Нательные датчики"</string>
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"доступ к данным датчиков о состоянии организма"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Получать содержимое окна"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Анализировать содержимое активного окна."</string>
@@ -1912,8 +1912,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Обновлено администратором"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Удалено администратором"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, некоторые визуальные эффекты, определенные функции и ряд сетевых подключений."</string>
- <string name="battery_saver_description" msgid="8518809702138617167">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, некоторые визуальные эффекты, определенные функции и ряд сетевых подключений."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, а также некоторые визуальные эффекты, функции и сетевые подключения."</string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, а также некоторые визуальные эффекты, функции и сетевые подключения."</string>
<string name="data_saver_description" msgid="4995164271550590517">"В режиме экономии трафика фоновая передача данных для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Включить экономию трафика?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Включить"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 4e188d9ff38a..1bad219e9cd5 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"හරි"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"බැටරි සුරැකුම අඳුරු තේමාව ක්‍රියාත්මක කර පසුබිම් ක්‍රියාකාරකම්, සමහර දෘශ්‍ය ප්‍රයෝග, යම් විශේෂාංග සහ සමහර ජාල සම්බන්ධතා සීමා හෝ ක්‍රියාවිරහිත කරයි."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"බැටරි සුරැකුම අඳුරු තේමාව ක්‍රියාත්මක කර පසුබිම් ක්‍රියාකාරකම්, සමහර දෘශ්‍ය ප්‍රයෝග, යම් විශේෂාංග සහ සමහර ජාල සම්බන්ධතා සීමා හෝ ක්‍රියාවිරහිත කරයි."</string>
<string name="data_saver_description" msgid="4995164271550590517">"දත්ත භාවිතය අඩු කිරීමට උදවු වීමට, දත්ත සුරැකුම සමහර යෙදුම් පසුබිමින් දත්ත යැවීම සහ ලබා ගැනීම වළක්වයි. ඔබ දැනට භාවිත කරන යෙදුමකට දත්ත වෙත පිවිසීමට හැකිය, නමුත් එසේ කරන්නේ කලාතුරකින් විය හැකිය. මෙයින් අදහස් වන්නේ, උදාහරණයක් ලෙස, එම රූප ඔබ ඒවාට තට්ටු කරන තෙක් සංදර්ශනය නොවන බවය."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"දත්ත සුරැකුම ක්‍රියාත්මක කරන්නද?"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 928ff129cf6e..ff114cd3e17f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1912,8 +1912,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty, určité funkcie a niektoré pripojenia k sieti."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty, určité funkcie a niektoré pripojenia k sieti."</string>
<string name="data_saver_description" msgid="4995164271550590517">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Môže to napríklad znamenať, že sa obrázky zobrazia, až keď na ne klepnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnúť šetrič dát?"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index ed33ec3324de..658ab8d7b57c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1912,8 +1912,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Posodobil skrbnik"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisal skrbnik"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Funkcija varčevanja z energijo baterije vklopi temno temo ter omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke, določene funkcije in nekatere omrežne povezave."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Funkcija varčevanja z energijo baterije vklopi temno temo ter omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke, določene funkcije in nekatere omrežne povezave."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Zaradi zmanjševanja prenesene količine podatkov funkcija varčevanja s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vklop varčevanja s podatki?"</string>
@@ -2036,8 +2035,8 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Več o tem"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Prekliči začasno zaustavitev aplikacije"</string>
<string name="work_mode_off_title" msgid="961171256005852058">"Vklop delovnih aplikacij?"</string>
- <string name="work_mode_off_message" msgid="7319580997683623309">"Omogočanje dostopa do delovnih aplikacij in obvestil za delovni profil"</string>
- <string name="work_mode_turn_on" msgid="3662561662475962285">"Vklop"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"Pridobite dostop do delovnih aplikacij in obvestil za delovni profil."</string>
+ <string name="work_mode_turn_on" msgid="3662561662475962285">"Vklopi"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija ni na voljo"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno ni na voljo."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ta aplikacija je bila zasnovana za starejšo različico Androida in morda ne bo delovala pravilno. Preverite, ali so na voljo posodobitve, ali pa se obrnite na razvijalca."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 34e4ead4ed2e..ad07eb6cb20a 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Përditësuar nga administratori"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Fshirë nga administratori"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Në rregull"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\" dhe kufizon ose çaktivizon aktivitetin në sfond, disa efekte vizuale, veçori të caktuara dhe disa lidhje të rrjetit."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\" dhe kufizon ose çaktivizon aktivitetin në sfond, disa efekte vizuale, veçori të caktuara dhe disa lidhje të rrjetit."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Për të ndihmuar në reduktimin e përdorimit të të dhënave, \"Kursyesi i të dhënave\" pengon që disa aplikacione të dërgojnë apo të marrin të dhëna në sfond. Një aplikacion që po përdor aktualisht mund të ketë qasje te të dhënat, por këtë mund ta bëjë më rrallë. Kjo mund të nënkuptojë, për shembull, se imazhet nuk shfaqen kur troket mbi to."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Të aktivizohet \"Kursyesi i të dhënave\"?"</string>
@@ -1972,7 +1971,7 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"Mëso më shumë"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anulo pauzën për aplikacionin"</string>
<string name="work_mode_off_title" msgid="961171256005852058">"Të aktivizohen aplikacionet e punës?"</string>
- <string name="work_mode_off_message" msgid="7319580997683623309">"Merr qasjen tek aplikacionet e punës dhe njoftimet e tua"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"Merr qasje tek aplikacionet e punës dhe njoftimet e tua"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivizo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacioni nuk ofrohet"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk ofrohet për momentin."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 458677ccf136..4d9dbd6b085c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1889,8 +1889,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирао је администратор"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Избрисао је администратор"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Потврди"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Уштеда батерије укључује тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте, одређене функције и неке мрежне везе."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Уштеда батерије укључује тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте, одређене функције и неке мрежне везе."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Желите да укључите Уштеду података?"</string>
@@ -2003,7 +2002,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"Апликација <xliff:g id="APP_NAME_0">%1$s</xliff:g> тренутно није доступна. <xliff:g id="APP_NAME_1">%2$s</xliff:g> управља доступношћу."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Сазнајте више"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Опозови паузирање апликације"</string>
- <string name="work_mode_off_title" msgid="961171256005852058">"Укључити пословне апликације?"</string>
+ <string name="work_mode_off_title" msgid="961171256005852058">"Укључујете пословне апликације?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Приступајте пословним апликацијама и обавештењима"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Укључи"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Апликација није доступна"</string>
@@ -2126,7 +2125,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Потврди"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Искључи"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Сазнајте више"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Побољшана обавештења су заменила Android прилагодљива обавештења у Android-у 12. Ова функција показује предложене радње и одговоре и организује обавештења.\n\nПобољшана обавештења могу да приступају садржају обавештења, укључујући личне податке попут имена контаката и порука. Ова функција може и да одбацује обавештења или да одговара на њих, на пример, да се јавља на телефонске позиве и контролише режим Не узнемиравај."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Побољшана обавештења су заменила Android прилагодљива обавештења у Android-у 12. Ова функција показује предложене радње и одговоре, и организује обавештења.\n\nПобољшана обавештења могу да приступају садржају обавештења, укључујући личне податке попут имена контаката и порука. Ова функција може и да одбацује обавештења или да одговара на њих, на пример, да се јавља на телефонске позиве и контролише режим Не узнемиравај."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Обавештење о информацијама Рутинског режима"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батерија ће се можда испразнити пре уобичајеног пуњења"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Уштеда батерије је активирана да би се продужило трајање батерије"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 944c86868f79..256c8ac955bc 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administratören uppdaterade paketet"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratören raderade paketet"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"I batterisparläget aktiveras mörkt tema medan bakgrundsaktivitet, vissa visuella effekter och funktioner samt vissa nätverksanslutningar begränsas eller inaktiveras."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"I batterisparläget aktiveras mörkt tema medan bakgrundsaktivitet, vissa visuella effekter och funktioner samt vissa nätverksanslutningar begränsas eller inaktiveras."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Med Databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vill du aktivera Databesparing?"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 41c4c0dcb161..7780c779372b 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Imesasishwa na msimamizi wako"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Imefutwa na msimamizi wako"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Sawa"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana, vipengele fulani na baadhi ya miunganisho ya mtandao."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana, vipengele fulani na baadhi ya miunganisho ya mtandao."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Ili kusaidia kupunguza matumizi ya data, Kiokoa Data huzuia baadhi ya programu kupokea na kutuma data chinichini. Programu ambayo unatumia sasa inaweza kufikia data, lakini si kila wakati. Kwa mfano, haitaonyesha picha hadi utakapozifungua."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ungependa Kuwasha Kiokoa Data?"</string>
@@ -1971,7 +1970,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> haipatikani kwa sasa. Inasimamiwa na <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Pata maelezo zaidi"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Acha kusimamisha programu"</string>
- <string name="work_mode_off_title" msgid="961171256005852058">"Utawasha programu za kazini?"</string>
+ <string name="work_mode_off_title" msgid="961171256005852058">"Iwashe programu za kazini?"</string>
<string name="work_mode_off_message" msgid="7319580997683623309">"Pata uwezo wa kufikia arifa na programu zako za kazini"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Washa"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 6fc392a7b213..f2ada5d4b2d8 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"சரி"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"பேட்டரி சேமிப்பான் அம்சம் டார்க் தீமை இயக்குவதோடு பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபக்ட்கள், குறிப்பிட்ட அம்சங்கள், சில நெட்வொர்க் இணைப்புகள் ஆகியவற்றைக் கட்டுப்படுத்தும் அல்லது முடக்கும்."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"பேட்டரி சேமிப்பான் டார்க் தீமினை ஆன் செய்து பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள், குறிப்பிட்ட அம்சங்கள், சில நெட்வொர்க் இணைப்புகள் ஆகியவற்றைக் கட்டுப்படுத்தும் அல்லது ஆஃப் செய்யும்."</string>
<string name="data_saver_description" msgid="4995164271550590517">"டேட்டா உபயோகத்தைக் குறைப்பதற்கு உதவ, பின்புலத்தில் டேட்டாவை அனுப்புவது அல்லது பெறுவதிலிருந்து சில ஆப்ஸை டேட்டா சேமிப்பான் தடுக்கும். தற்போது பயன்படுத்தும் ஆப்ஸானது எப்போதாவது டேட்டாவை அணுகலாம். எடுத்துக்காட்டாக, படங்களை நீங்கள் தட்டும் வரை அவை காட்டப்படாது."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"டேட்டா சேமிப்பானை இயக்கவா?"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 4a2c0f9f21c0..7a363f10f76c 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"మీ నిర్వాహకులు నవీకరించారు"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేసి, బ్యాక్‌గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్‌లు, నిర్దిష్ట ఫీచర్‌లు, ఇంకా కొన్ని నెట్‌వర్క్ కనెక్షన్‌లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేసి, బ్యాక్‌గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్‌లు, నిర్దిష్ట ఫీచర్‌లు, ఇంకా కొన్ని నెట్‌వర్క్ కనెక్షన్‌లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది."</string>
<string name="data_saver_description" msgid="4995164271550590517">"డేటా వినియోగాన్ని తగ్గించడంలో డేటా సేవర్ సహాయకరంగా ఉంటుంది. బ్యాక్‌గ్రౌండ్‌లో కొన్ని యాప్‌లు డేటాను పంపకుండా లేదా స్వీకరించకుండా నిరోధిస్తుంది. మీరు ప్రస్తుతం ఉపయోగిస్తోన్న యాప్‌, డేటాను యాక్సెస్ చేయగలదు. కానీ త‌క్కువ సార్లు మాత్ర‌మే అలా చేయవచ్చు. ఉదాహరణకు, మీరు నొక్కే వరకు ఫోటోలు ప్రదర్శించబడవు."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"డేటా సేవర్‌ను ఆన్ చేయాలా?"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 58dc371f7682..9f3f9c374691 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"อัปเดตโดยผู้ดูแลระบบ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง ฟีเจอร์บางส่วน และการเชื่อมต่อบางเครือข่าย"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง ฟีเจอร์บางส่วน และการเชื่อมต่อบางเครือข่าย"</string>
<string name="data_saver_description" msgid="4995164271550590517">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 88adb5064478..3c41e39ca202 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ٹھیک ہے"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"بیٹری سیور گہری تھیم کو آن کرتی ہے اور پس منظر کی سرگرمی، کچھ بصری اثرات، مخصوص خصوصیات اور کچھ نیٹ ورک کنکشنز کو محدود یا آف کرتی ہے۔"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"بیٹری سیور گہری تھیم کو آن کرتی ہے اور پس منظر کی سرگرمی، کچھ بصری اثرات، مخصوص خصوصیات اور کچھ نیٹ ورک کنکشنز کو محدود یا آف کرتی ہے۔"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ڈیٹا کے استعمال کو کم کرنے میں مدد کیلئے، ڈیٹا سیور پس منظر میں کچھ ایپس کو ڈیٹا بھیجنے یا موصول کرنے سے روکتی ہے۔ آپ جو ایپ فی الحال استعمال کر رہے ہیں وہ ڈیٹا تک رسائی کر سکتی ہے مگر ہو سکتا ہے ایسا اکثر نہ ہو۔ اس کا مطلب مثال کے طور پر یہ ہو سکتا ہے کہ تصاویر تھپتھپانے تک ظاہر نہ ہوں۔"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ڈیٹا سیور آن کریں؟"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index aea9b5728152..9fee7d85f252 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administrator tomonidan yangilangan"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administrator tomonidan o‘chirilgan"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi hamda fondagi harakatlar, vizual effektlar, ayrim funksiyalar va tarmoq aloqalari kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi hamda fondagi harakatlar, vizual effektlar, ayrim funksiyalar va tarmoq aloqalari kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Trafik tejash rejimida ayrim ilovalar uchun orqa fonda internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Trafik tejash yoqilsinmi?"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 7df4ebca93e3..7e9c54be5c1d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Do quản trị viên của bạn cập nhật"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Do quản trị viên của bạn xóa"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Trình tiết kiệm pin sẽ bật Giao diện tối, đồng thời hạn chế hoặc tắt hoạt động chạy trong nền, một số hiệu ứng hình ảnh, các tính năng nhất định và một số đường kết nối mạng."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Trình tiết kiệm pin sẽ bật Giao diện tối, đồng thời hạn chế hoặc tắt hoạt động chạy trong nền, một số hiệu ứng hình ảnh, các tính năng nhất định, và một số kết nối mạng."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu sẽ chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể dùng dữ liệu nhưng tần suất sẽ giảm. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Bật Trình tiết kiệm dữ liệu?"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 576ec6a6a74a..762607064c7e 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"好"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"「省電模式」會開啟深色主題背景,並限制或關閉背景活動、部分視覺效果、特定功能和部分網絡連線。"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"「省電模式」會開啟深色主題背景,並限制或關閉背景活動、部分視覺效果、特定功能和部分網絡連線。"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟「數據節省模式」嗎?"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 5da2ca5df9ac..52ffc605ec63 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1866,8 +1866,7 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (5444908404021316250) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果、特定功能和部分網路連線。"</string>
<string name="battery_saver_description" msgid="8518809702138617167">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果、特定功能和部分網路連線。"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟數據節省模式嗎?"</string>
@@ -2093,7 +2092,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"確定"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"關閉"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"瞭解詳情"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"在 Android 12 中,加強型通知功能已取代 Android 自動調整通知。這項功能可以顯示建議的操作和回覆內容,也可以整理通知。\n\n加強型通知功能可存取通知內容,包括聯絡人名稱和訊息內文等個人資訊。此外,這項功能還能關閉或回覆通知,例如接聽來電及控管「零打擾」功能。"</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"在 Android 12 中,加強型通知功能已取代 Android 自動調整通知。這項功能可以顯示建議的操作和回覆內容,也可以幫你整理通知訊息。\n\n加強型通知功能可存取通知內容,包括聯絡人名稱和訊息內文等個人資訊。此外,這項功能還能關閉或回覆通知,例如接聽來電及控管「零打擾」功能。"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式資訊通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電池電力可能會在你平常的充電時間前耗盡"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用省電模式以延長電池續航力"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bc63df659903..bf59f4d7e756 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1759,6 +1759,13 @@
<item>com.android.location.fused</item>
</string-array>
+ <!-- Package name(s) of Advanced Driver Assistance applications. These packages have additional
+ management of access to location, specific to driving assistance use-cases. They must be system
+ packages. This configuration is only applicable to devices that declare
+ PackageManager.FEATURE_AUTOMOTIVE. -->
+ <string-array name="config_locationDriverAssistancePackageNames" translatable="false">
+ </string-array>
+
<!-- This string array can be overriden to enable test location providers initially. -->
<!-- Array of "[locationProviderName],[requiresNetwork],
[requiresSatellite],[requiresCell],[hasMonetaryCost],
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 49ed21399d3d..7006d930995f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1899,6 +1899,7 @@
<java-symbol type="array" name="radioAttributes" />
<java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="array" name="config_locationProviderPackageNames" />
+ <java-symbol type="array" name="config_locationDriverAssistancePackageNames" />
<java-symbol type="array" name="config_locationExtraPackageNames" />
<java-symbol type="array" name="config_testLocationProviders" />
<java-symbol type="array" name="config_defaultNotificationVibePattern" />
diff --git a/core/tests/coretests/apks/overlay_config/Android.bp b/core/tests/coretests/apks/overlay_config/Android.bp
index 9c971fd2f1bc..07775239d6ed 100644
--- a/core/tests/coretests/apks/overlay_config/Android.bp
+++ b/core/tests/coretests/apks/overlay_config/Android.bp
@@ -10,4 +10,5 @@ package {
android_test_helper_app {
name: "FrameworksCoreTests_overlay_config",
defaults: ["FrameworksCoreTests_apks_defaults"],
+ min_sdk_version: "20",
}
diff --git a/core/tests/coretests/apks/overlay_config/AndroidManifest.xml b/core/tests/coretests/apks/overlay_config/AndroidManifest.xml
index b15338eb545b..092a5754286f 100644
--- a/core/tests/coretests/apks/overlay_config/AndroidManifest.xml
+++ b/core/tests/coretests/apks/overlay_config/AndroidManifest.xml
@@ -19,7 +19,7 @@
<application android:hasCode="false" />
- <uses-sdk android:targetSdkVersion="21"/>
+ <uses-sdk android:minSdkVersion="20" android:targetSdkVersion="21"/>
<overlay android:targetPackage="android"
android:targetName="TestResources" />
diff --git a/core/tests/coretests/apks/overlay_config/OWNERS b/core/tests/coretests/apks/overlay_config/OWNERS
new file mode 100644
index 000000000000..3e79d8ff0bbe
--- /dev/null
+++ b/core/tests/coretests/apks/overlay_config/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/res/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OWNERS b/core/tests/coretests/src/com/android/internal/content/res/OWNERS
new file mode 100644
index 000000000000..3e79d8ff0bbe
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/content/res/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/res/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
index a01459f20f6b..c50c818be716 100644
--- a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.content;
+package com.android.internal.content.res;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
diff --git a/core/tests/coretests/src/com/android/internal/content/OverlayConfigTest.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
index dee118fbe0fe..178c2dd5b062 100644
--- a/core/tests/coretests/src/com/android/internal/content/OverlayConfigTest.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.content;
+package com.android.internal.content.res;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
diff --git a/data/etc/car/com.android.car.shell.xml b/data/etc/car/com.android.car.shell.xml
index d48d7515f22a..c058cb91cf9d 100644
--- a/data/etc/car/com.android.car.shell.xml
+++ b/data/etc/car/com.android.car.shell.xml
@@ -33,5 +33,8 @@
<permission name="android.car.permission.CONTROL_CAR_EVS_ACTIVITY" />
<permission name="android.car.permission.USE_CAR_EVS_CAMERA" />
<permission name="android.car.permission.MONITOR_CAR_EVS_STATUS" />
+ <permission name="android.car.permission.USE_CAR_WATCHDOG" />
+ <permission name="android.car.permission.COLLECT_CAR_WATCHDOG_METRICS" />
+ <permission name="android.car.permission.CONTROL_CAR_WATCHDOG_CONFIG" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 99d71675ffa9..240d0565bddb 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -497,6 +497,8 @@ applications that come with the platform
<privapp-permissions package="com.android.statementservice">
<permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
+ <permission name="android.permission.DOMAIN_VERIFICATION_AGENT"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
</privapp-permissions>
<privapp-permissions package="com.android.traceur">
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 73e65c2ec050..0d8715bfaef2 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -182,6 +182,7 @@ public class RippleDrawable extends LayerDrawable {
private Canvas mMaskCanvas;
private Matrix mMaskMatrix;
private PorterDuffColorFilter mMaskColorFilter;
+ private PorterDuffColorFilter mFocusColorFilter;
private boolean mHasValidMask;
private int mComputedRadius = -1;
@@ -938,7 +939,7 @@ public class RippleDrawable extends LayerDrawable {
final int alpha = Math.min((int) (origAlpha * newOpacity + 0.5f), 255);
if (alpha > 0) {
ColorFilter origFilter = p.getColorFilter();
- p.setColorFilter(mMaskColorFilter);
+ p.setColorFilter(mFocusColorFilter);
p.setAlpha(alpha);
c.drawCircle(cx, cy, getComputedRadius(), p);
p.setAlpha(origAlpha);
@@ -1091,6 +1092,7 @@ public class RippleDrawable extends LayerDrawable {
if (mMaskColorFilter == null) {
mMaskColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_IN);
+ mFocusColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_IN);
}
// Draw the appropriate mask anchored to (0,0).
@@ -1219,6 +1221,8 @@ public class RippleDrawable extends LayerDrawable {
int maskColor = mState.mRippleStyle == STYLE_PATTERNED ? color : color | 0xFF000000;
if (mMaskColorFilter.getColor() != maskColor) {
mMaskColorFilter = new PorterDuffColorFilter(maskColor, mMaskColorFilter.getMode());
+ mFocusColorFilter = new PorterDuffColorFilter(color | 0xFF000000,
+ mFocusColorFilter.getMode());
}
p.setColor(color & 0xFF000000);
p.setColorFilter(mMaskColorFilter);
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 0e02541fa892..6d3e0a92d2ce 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -45,10 +45,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yuxarı 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Yuxarı 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Aşağı tam ekran"</string>
- <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bir əlli rejimdən istifadə edilir"</string>
+ <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Birəlli rejim istifadəsi"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Çıxmaq üçün ekranın aşağısından yuxarıya doğru sürüşdürün və ya tətbiqin yuxarısında istənilən yerə toxunun"</string>
- <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bir əlli rejimi başladın"</string>
- <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Bir əlli rejimdən çıxın"</string>
+ <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Birəlli rejim başlasın"</string>
+ <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Birəlli rejimdən çıxın"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> yumrucuqları üçün ayarlar"</string>
<string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Kənara çıxma"</string>
<string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Yenidən dəstəyə əlavə edin"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
index 176c620fa119..798250de89d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
@@ -312,6 +312,13 @@ public class FlingAnimationUtils {
}
/**
+ * @return a velocity considered fast
+ */
+ public float getHighVelocityPxPerSecond() {
+ return mHighVelocityPxPerSecond;
+ }
+
+ /**
* An interpolator which interpolates two interpolators with an interpolator.
*/
private static final class InterpolatorInterpolator implements Interpolator {
diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml
index 9922fe117f88..f5ad2be44193 100644
--- a/packages/PackageInstaller/res/values-eu/strings.xml
+++ b/packages/PackageInstaller/res/values-eu/strings.xml
@@ -46,7 +46,7 @@
<string name="out_of_space_dlg_text" msgid="8727714096031856231">"Ezin izan da instalatu <xliff:g id="APP_NAME">%1$s</xliff:g>. Egin toki pixka bat eta saiatu berriro."</string>
<string name="app_not_found_dlg_title" msgid="5107924008597470285">"Ez da aurkitu aplikazioa"</string>
<string name="app_not_found_dlg_text" msgid="5219983779377811611">"Ez da aurkitu aplikazioa instalatutako aplikazioen zerrendan."</string>
- <string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"Ez du baimenik"</string>
+ <string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"Baimendu gabe"</string>
<string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"Erabiltzaile honek ez dauka desinstalatzeko baimenik."</string>
<string name="generic_error_dlg_title" msgid="5863195085927067752">"Errorea"</string>
<string name="generic_error_dlg_text" msgid="5287861443265795232">"Ezin izan da desinstalatu aplikazioa."</string>
diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml
index 637e15a6c656..ac1f6acd6eaa 100644
--- a/packages/PackageInstaller/res/values-gl/strings.xml
+++ b/packages/PackageInstaller/res/values-gl/strings.xml
@@ -46,7 +46,7 @@
<string name="out_of_space_dlg_text" msgid="8727714096031856231">"Non se puido instalar a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>. Libera espazo e téntao de novo."</string>
<string name="app_not_found_dlg_title" msgid="5107924008597470285">"Non se atopou a aplicación"</string>
<string name="app_not_found_dlg_text" msgid="5219983779377811611">"Non se atopou a aplicación na lista de aplicacións instaladas."</string>
- <string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"Sen permiso"</string>
+ <string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"Permiso non concedido"</string>
<string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"O usuario actual non pode realizar esta desinstalación."</string>
<string name="generic_error_dlg_title" msgid="5863195085927067752">"Erro"</string>
<string name="generic_error_dlg_text" msgid="5287861443265795232">"Non se puido desinstalar a aplicación."</string>
diff --git a/packages/Shell/res/values-az/strings.xml b/packages/Shell/res/values-az/strings.xml
index 1522f3febca6..15853c2cc270 100644
--- a/packages/Shell/res/values-az/strings.xml
+++ b/packages/Shell/res/values-az/strings.xml
@@ -29,7 +29,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"baq hesabatınızı skrinşot olmadan paylaşmaq üçün tıklayın, skrinşotun tamamlanması üçün isə gözləyin"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"baq hesabatınızı skrinşot olmadan paylaşmaq üçün tıklayın, skrinşotun tamamlanması üçün isə gözləyin"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Baq hesabatları sistemin müxtəlif jurnal fayllarından həssas təyin etdiyiniz data (tətbiq istifadəsi və məkan datası kimi) içərir. Baq raportlarını yalnız inandığınız tətbiq və adamlarla paylaşın."</string>
- <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Daha göstərməyin"</string>
+ <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Göstərilməsin"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Baq hesabatları"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Baq hesabat faylı oxunmur"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Zip faylı üçün baq hesabat detalları əlavə edilmədi"</string>
diff --git a/packages/StatementService/Android.bp b/packages/StatementService/Android.bp
index 32defc822733..a0d8ac9b8adc 100644
--- a/packages/StatementService/Android.bp
+++ b/packages/StatementService/Android.bp
@@ -22,17 +22,24 @@ package {
android_app {
name: "StatementService",
- defaults: ["platform_app_defaults"],
- srcs: ["src/**/*.java"],
+ // Removed because Errorprone doesn't work with Kotlin, can fix up in the future
+ // defaults: ["platform_app_defaults"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
optimize: {
proguard_flags_files: ["proguard.flags"],
},
+ target_sdk_version: "29",
platform_apis: true,
privileged: true,
- libs: ["org.apache.http.legacy"],
- uses_libs: ["org.apache.http.legacy"],
+ certificate: "platform",
static_libs: [
- "libprotobuf-java-nano",
- "volley",
+ "androidx.appcompat_appcompat",
+ "androidx.collection_collection-ktx",
+ "androidx.work_work-runtime",
+ "androidx.work_work-runtime-ktx",
+ "kotlinx-coroutines-android",
],
}
diff --git a/packages/StatementService/AndroidManifest.xml b/packages/StatementService/AndroidManifest.xml
index e0abd50b9de9..42cd14314954 100644
--- a/packages/StatementService/AndroidManifest.xml
+++ b/packages/StatementService/AndroidManifest.xml
@@ -14,41 +14,62 @@
limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.statementservice"
- android:versionCode="1"
- android:versionName="1.0">
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.statementservice"
+ android:versionCode="1"
+ android:versionName="1.0">
- <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.DOMAIN_VERIFICATION_AGENT"/>
<uses-permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+ <uses-permission android:name="android.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION"/>
<application
- android:label="@string/service_name"
- android:allowBackup="false">
- <uses-library android:name="org.apache.http.legacy" />
- <service
- android:name=".DirectStatementService"
- android:exported="false">
+ android:label="@string/service_name"
+ android:allowBackup="false"
+ android:name=".StatementServiceApplication"
+ >
+
+ <receiver
+ android:name=".domain.BootCompletedReceiver"
+ android:exported="true">
<intent-filter>
- <category android:name="android.intent.category.DEFAULT"/>
- <action android:name="com.android.statementservice.aosp.service.CHECK_ACTION"/>
+ <action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
- </service>
+ </receiver>
<receiver
- android:name=".IntentFilterVerificationReceiver"
- android:permission="android.permission.BIND_INTENT_FILTER_VERIFIER"
- android:exported="true">
- <!-- Set the priority 1 so newer implementation can have higher priority. -->
- <intent-filter
- android:priority="1">
+ android:name=".domain.DomainVerificationReceiverV1"
+ android:permission="android.permission.BIND_INTENT_FILTER_VERIFIER"
+ android:exported="true"
+ >
+ <intent-filter android:priority="1">
<action android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION"/>
<data android:mimeType="application/vnd.android.package-archive"/>
</intent-filter>
</receiver>
+ <!--
+ v2 receiver remains disabled assuming the device ships its own updated version.
+ If necessary, this can be enabled using shell.
+ -->
+ <receiver
+ android:name=".domain.DomainVerificationReceiverV2"
+ android:permission="android.permission.BIND_DOMAIN_VERIFICATION_AGENT"
+ android:directBootAware="true"
+ android:exported="true"
+ android:enabled="false"
+ >
+ <intent-filter android:priority="1">
+ <action android:name="android.intent.action.DOMAINS_NEED_VERIFICATION"/>
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/packages/StatementService/src/com/android/statementservice/DirectStatementService.java b/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
deleted file mode 100644
index 659696e0e212..000000000000
--- a/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice;
-
-import android.app.Service;
-import android.content.Intent;
-import android.net.http.HttpResponseCache;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.ResultReceiver;
-import android.util.Log;
-
-import com.android.statementservice.retriever.AbstractAsset;
-import com.android.statementservice.retriever.AbstractAssetMatcher;
-import com.android.statementservice.retriever.AbstractStatementRetriever;
-import com.android.statementservice.retriever.AbstractStatementRetriever.Result;
-import com.android.statementservice.retriever.AssociationServiceException;
-import com.android.statementservice.retriever.Relation;
-import com.android.statementservice.retriever.Statement;
-
-import org.json.JSONException;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-/**
- * Handles com.android.statementservice.service.CHECK_ALL_ACTION intents.
- */
-public final class DirectStatementService extends Service {
- private static final String TAG = DirectStatementService.class.getSimpleName();
-
- /**
- * Returns true if every asset in {@code SOURCE_ASSET_DESCRIPTORS} is associated with {@code
- * EXTRA_TARGET_ASSET_DESCRIPTOR} for {@code EXTRA_RELATION} relation.
- *
- * <p>Takes parameter {@code EXTRA_RELATION}, {@code SOURCE_ASSET_DESCRIPTORS}, {@code
- * EXTRA_TARGET_ASSET_DESCRIPTOR}, and {@code EXTRA_RESULT_RECEIVER}.
- */
- public static final String CHECK_ALL_ACTION =
- "com.android.statementservice.service.CHECK_ALL_ACTION";
-
- /**
- * Parameter for {@link #CHECK_ALL_ACTION}.
- *
- * <p>A relation string.
- */
- public static final String EXTRA_RELATION =
- "com.android.statementservice.service.RELATION";
-
- /**
- * Parameter for {@link #CHECK_ALL_ACTION}.
- *
- * <p>An array of asset descriptors in JSON.
- */
- public static final String EXTRA_SOURCE_ASSET_DESCRIPTORS =
- "com.android.statementservice.service.SOURCE_ASSET_DESCRIPTORS";
-
- /**
- * Parameter for {@link #CHECK_ALL_ACTION}.
- *
- * <p>An asset descriptor in JSON.
- */
- public static final String EXTRA_TARGET_ASSET_DESCRIPTOR =
- "com.android.statementservice.service.TARGET_ASSET_DESCRIPTOR";
-
- /**
- * Parameter for {@link #CHECK_ALL_ACTION}.
- *
- * <p>A {@code ResultReceiver} instance that will be used to return the result. If the request
- * failed, return {@link #RESULT_FAIL} and an empty {@link android.os.Bundle}. Otherwise, return
- * {@link #RESULT_SUCCESS} and a {@link android.os.Bundle} with the result stored in {@link
- * #IS_ASSOCIATED}.
- */
- public static final String EXTRA_RESULT_RECEIVER =
- "com.android.statementservice.service.RESULT_RECEIVER";
-
- /**
- * A boolean bundle entry that stores the result of {@link #CHECK_ALL_ACTION}.
- * This is set only if the service returns with {@code RESULT_SUCCESS}.
- * {@code IS_ASSOCIATED} is true if and only if {@code FAILED_SOURCES} is empty.
- */
- public static final String IS_ASSOCIATED = "is_associated";
-
- /**
- * A String ArrayList bundle entry that stores sources that can't be verified.
- */
- public static final String FAILED_SOURCES = "failed_sources";
-
- /**
- * Returned by the service if the request is successfully processed. The caller should check
- * the {@code IS_ASSOCIATED} field to determine if the association exists or not.
- */
- public static final int RESULT_SUCCESS = 0;
-
- /**
- * Returned by the service if the request failed. The request will fail if, for example, the
- * input is not well formed, or the network is not available.
- */
- public static final int RESULT_FAIL = 1;
-
- private static final long HTTP_CACHE_SIZE_IN_BYTES = 1 * 1024 * 1024; // 1 MBytes
- private static final String CACHE_FILENAME = "request_cache";
-
- private AbstractStatementRetriever mStatementRetriever;
- private Handler mHandler;
- private HandlerThread mThread;
- private HttpResponseCache mHttpResponseCache;
-
- @Override
- public void onCreate() {
- mThread = new HandlerThread("DirectStatementService thread",
- android.os.Process.THREAD_PRIORITY_BACKGROUND);
- mThread.start();
- onCreate(AbstractStatementRetriever.createDirectRetriever(this), mThread.getLooper(),
- getCacheDir());
- }
-
- /**
- * Creates a DirectStatementService with the dependencies passed in for easy testing.
- */
- public void onCreate(AbstractStatementRetriever statementRetriever, Looper looper,
- File cacheDir) {
- super.onCreate();
- mStatementRetriever = statementRetriever;
- mHandler = new Handler(looper);
-
- try {
- File httpCacheDir = new File(cacheDir, CACHE_FILENAME);
- mHttpResponseCache = HttpResponseCache.install(httpCacheDir, HTTP_CACHE_SIZE_IN_BYTES);
- } catch (IOException e) {
- Log.i(TAG, "HTTPS response cache installation failed:" + e);
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- final HttpResponseCache responseCache = mHttpResponseCache;
- mHandler.post(new Runnable() {
- public void run() {
- try {
- if (responseCache != null) {
- responseCache.delete();
- }
- } catch (IOException e) {
- Log.i(TAG, "HTTP(S) response cache deletion failed:" + e);
- }
- Looper.myLooper().quit();
- }
- });
- mHttpResponseCache = null;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- super.onStartCommand(intent, flags, startId);
-
- if (intent == null) {
- Log.e(TAG, "onStartCommand called with null intent");
- return START_STICKY;
- }
-
- if (intent.getAction().equals(CHECK_ALL_ACTION)) {
-
- Bundle extras = intent.getExtras();
- List<String> sources = extras.getStringArrayList(EXTRA_SOURCE_ASSET_DESCRIPTORS);
- String target = extras.getString(EXTRA_TARGET_ASSET_DESCRIPTOR);
- String relation = extras.getString(EXTRA_RELATION);
- ResultReceiver resultReceiver = extras.getParcelable(EXTRA_RESULT_RECEIVER);
-
- if (resultReceiver == null) {
- Log.e(TAG, " Intent does not have extra " + EXTRA_RESULT_RECEIVER);
- return START_STICKY;
- }
- if (sources == null) {
- Log.e(TAG, " Intent does not have extra " + EXTRA_SOURCE_ASSET_DESCRIPTORS);
- resultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
- return START_STICKY;
- }
- if (target == null) {
- Log.e(TAG, " Intent does not have extra " + EXTRA_TARGET_ASSET_DESCRIPTOR);
- resultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
- return START_STICKY;
- }
- if (relation == null) {
- Log.e(TAG, " Intent does not have extra " + EXTRA_RELATION);
- resultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
- return START_STICKY;
- }
-
- mHandler.post(new ExceptionLoggingFutureTask<Void>(
- new IsAssociatedCallable(sources, target, relation, resultReceiver), TAG));
- } else {
- Log.e(TAG, "onStartCommand called with unsupported action: " + intent.getAction());
- }
- return START_STICKY;
- }
-
- private class IsAssociatedCallable implements Callable<Void> {
-
- private List<String> mSources;
- private String mTarget;
- private String mRelation;
- private ResultReceiver mResultReceiver;
-
- public IsAssociatedCallable(List<String> sources, String target, String relation,
- ResultReceiver resultReceiver) {
- mSources = sources;
- mTarget = target;
- mRelation = relation;
- mResultReceiver = resultReceiver;
- }
-
- private boolean verifyOneSource(AbstractAsset source, AbstractAssetMatcher target,
- Relation relation) throws AssociationServiceException {
- Result statements = mStatementRetriever.retrieveStatements(source);
- for (Statement statement : statements.getStatements()) {
- if (relation.matches(statement.getRelation())
- && target.matches(statement.getTarget())) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public Void call() {
- Bundle result = new Bundle();
- ArrayList<String> failedSources = new ArrayList<String>();
- AbstractAssetMatcher target;
- Relation relation;
- try {
- target = AbstractAssetMatcher.createMatcher(mTarget);
- relation = Relation.create(mRelation);
- } catch (AssociationServiceException | JSONException e) {
- Log.e(TAG, "isAssociatedCallable failed with exception", e);
- mResultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
- return null;
- }
-
- boolean allSourcesVerified = true;
- for (String sourceString : mSources) {
- AbstractAsset source;
- try {
- source = AbstractAsset.create(sourceString);
- } catch (AssociationServiceException e) {
- mResultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
- return null;
- }
-
- try {
- if (!verifyOneSource(source, target, relation)) {
- failedSources.add(source.toJson());
- allSourcesVerified = false;
- }
- } catch (AssociationServiceException e) {
- failedSources.add(source.toJson());
- allSourcesVerified = false;
- }
- }
-
- result.putBoolean(IS_ASSOCIATED, allSourcesVerified);
- result.putStringArrayList(FAILED_SOURCES, failedSources);
- mResultReceiver.send(RESULT_SUCCESS, result);
- return null;
- }
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/ExceptionLoggingFutureTask.java b/packages/StatementService/src/com/android/statementservice/ExceptionLoggingFutureTask.java
deleted file mode 100644
index 20c7f9715895..000000000000
--- a/packages/StatementService/src/com/android/statementservice/ExceptionLoggingFutureTask.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice;
-
-import android.util.Log;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-
-/**
- * {@link FutureTask} that logs unhandled exceptions.
- */
-final class ExceptionLoggingFutureTask<V> extends FutureTask<V> {
-
- private final String mTag;
-
- public ExceptionLoggingFutureTask(Callable<V> callable, String tag) {
- super(callable);
- mTag = tag;
- }
-
- @Override
- protected void done() {
- try {
- get();
- } catch (ExecutionException | InterruptedException e) {
- Log.e(mTag, "Uncaught exception.", e);
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java b/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
deleted file mode 100644
index ba8e7a1d3db3..000000000000
--- a/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Patterns;
-
-import com.android.statementservice.retriever.Utils;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * Receives {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION} broadcast and calls
- * {@link DirectStatementService} to verify the request. Calls
- * {@link PackageManager#verifyIntentFilter} to notify {@link PackageManager} the result of the
- * verification.
- *
- * This implementation of the API will send a HTTP request for each host specified in the query.
- * To avoid overwhelming the network at app install time, {@code MAX_HOSTS_PER_REQUEST} limits
- * the maximum number of hosts in a query. If a query contains more than
- * {@code MAX_HOSTS_PER_REQUEST} hosts, it will fail immediately without making any HTTP request
- * and call {@link PackageManager#verifyIntentFilter} with
- * {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
- */
-public final class IntentFilterVerificationReceiver extends BroadcastReceiver {
- private static final String TAG = IntentFilterVerificationReceiver.class.getSimpleName();
-
- private static final Integer MAX_HOSTS_PER_REQUEST = 10;
-
- private static final String HANDLE_ALL_URLS_RELATION
- = "delegate_permission/common.handle_all_urls";
-
- private static final String ANDROID_ASSET_FORMAT = "{\"namespace\": \"android_app\", "
- + "\"package_name\": \"%s\", \"sha256_cert_fingerprints\": [\"%s\"]}";
- private static final String WEB_ASSET_FORMAT = "{\"namespace\": \"web\", \"site\": \"%s\"}";
- private static final Pattern ANDROID_PACKAGE_NAME_PATTERN =
- Pattern.compile("^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)*$");
- private static final String TOO_MANY_HOSTS_FORMAT =
- "Request contains %d hosts which is more than the allowed %d.";
-
- private static void sendErrorToPackageManager(PackageManager packageManager,
- int verificationId) {
- packageManager.verifyIntentFilter(verificationId,
- PackageManager.INTENT_FILTER_VERIFICATION_FAILURE,
- Collections.<String>emptyList());
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION.equals(action)) {
- Bundle inputExtras = intent.getExtras();
- if (inputExtras != null) {
- Intent serviceIntent = new Intent(context, DirectStatementService.class);
- serviceIntent.setAction(DirectStatementService.CHECK_ALL_ACTION);
-
- int verificationId = inputExtras.getInt(
- PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID);
- String scheme = inputExtras.getString(
- PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME);
- String hosts = inputExtras.getString(
- PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS);
- String packageName = inputExtras.getString(
- PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME);
-
- Bundle extras = new Bundle();
- extras.putString(DirectStatementService.EXTRA_RELATION, HANDLE_ALL_URLS_RELATION);
-
- String[] hostList = hosts.split(" ");
- if (hostList.length > MAX_HOSTS_PER_REQUEST) {
- Log.w(TAG, String.format(TOO_MANY_HOSTS_FORMAT,
- hostList.length, MAX_HOSTS_PER_REQUEST));
- sendErrorToPackageManager(context.getPackageManager(), verificationId);
- return;
- }
-
- ArrayList<String> finalHosts = new ArrayList<String>(hostList.length);
- try {
- ArrayList<String> sourceAssets = new ArrayList<String>();
- for (String host : hostList) {
- // "*.example.tld" is validated via https://example.tld
- if (host.startsWith("*.")) {
- host = host.substring(2);
- }
- sourceAssets.add(createWebAssetString(scheme, host));
- finalHosts.add(host);
- }
- extras.putStringArrayList(DirectStatementService.EXTRA_SOURCE_ASSET_DESCRIPTORS,
- sourceAssets);
- } catch (MalformedURLException e) {
- Log.w(TAG, "Error when processing input host: " + e.getMessage());
- sendErrorToPackageManager(context.getPackageManager(), verificationId);
- return;
- }
- try {
- extras.putString(DirectStatementService.EXTRA_TARGET_ASSET_DESCRIPTOR,
- createAndroidAssetString(context, packageName));
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Error when processing input Android package: " + e.getMessage());
- sendErrorToPackageManager(context.getPackageManager(), verificationId);
- return;
- }
- extras.putParcelable(DirectStatementService.EXTRA_RESULT_RECEIVER,
- new IsAssociatedResultReceiver(
- new Handler(), context.getPackageManager(), verificationId));
-
- // Required for CTS: log a few details of the validcation operation to be performed
- logValidationParametersForCTS(verificationId, scheme, finalHosts, packageName);
-
- serviceIntent.putExtras(extras);
- context.startService(serviceIntent);
- }
- } else {
- Log.w(TAG, "Intent action not supported: " + action);
- }
- }
-
- // CTS requirement: logging of the validation parameters in a specific format
- private static final String CTS_LOG_FORMAT =
- "Verifying IntentFilter. verificationId:%d scheme:\"%s\" hosts:\"%s\" package:\"%s\".";
- private void logValidationParametersForCTS(int verificationId, String scheme,
- ArrayList<String> finalHosts, String packageName) {
- String hostString = TextUtils.join(" ", finalHosts.toArray());
- Log.i(TAG, String.format(CTS_LOG_FORMAT, verificationId, scheme, hostString, packageName));
- }
-
- private String createAndroidAssetString(Context context, String packageName)
- throws NameNotFoundException {
- if (!ANDROID_PACKAGE_NAME_PATTERN.matcher(packageName).matches()) {
- throw new NameNotFoundException("Input package name is not valid.");
- }
-
- List<String> certFingerprints =
- Utils.getCertFingerprintsFromPackageManager(packageName, context);
-
- return String.format(ANDROID_ASSET_FORMAT, packageName,
- Utils.joinStrings("\", \"", certFingerprints));
- }
-
- private String createWebAssetString(String scheme, String host) throws MalformedURLException {
- if (!Patterns.DOMAIN_NAME.matcher(host).matches()) {
- throw new MalformedURLException("Input host is not valid.");
- }
- if (!scheme.equals("http") && !scheme.equals("https")) {
- throw new MalformedURLException("Input scheme is not valid.");
- }
-
- return String.format(WEB_ASSET_FORMAT, new URL(scheme, host, "").toString());
- }
-
- /**
- * Receives the result of {@code StatementService.CHECK_ACTION} from
- * {@link DirectStatementService} and passes it back to {@link PackageManager}.
- */
- private static class IsAssociatedResultReceiver extends ResultReceiver {
-
- private final int mVerificationId;
- private final PackageManager mPackageManager;
-
- public IsAssociatedResultReceiver(Handler handler, PackageManager packageManager,
- int verificationId) {
- super(handler);
- mVerificationId = verificationId;
- mPackageManager = packageManager;
- }
-
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (resultCode == DirectStatementService.RESULT_SUCCESS) {
- if (resultData.getBoolean(DirectStatementService.IS_ASSOCIATED)) {
- mPackageManager.verifyIntentFilter(mVerificationId,
- PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS,
- Collections.<String>emptyList());
- } else {
- mPackageManager.verifyIntentFilter(mVerificationId,
- PackageManager.INTENT_FILTER_VERIFICATION_FAILURE,
- resultData.getStringArrayList(DirectStatementService.FAILED_SOURCES));
- }
- } else {
- sendErrorToPackageManager(mPackageManager, mVerificationId);
- }
- }
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/StatementServiceApplication.kt b/packages/StatementService/src/com/android/statementservice/StatementServiceApplication.kt
new file mode 100644
index 000000000000..021a5143c09a
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/StatementServiceApplication.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 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.statementservice
+
+import android.app.Application
+import android.os.UserManager
+import androidx.work.WorkManager
+import com.android.statementservice.domain.DomainVerificationUtils
+
+class StatementServiceApplication : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+ val userManager = getSystemService(UserManager::class.java) ?: return
+ if (userManager.isUserUnlocked) {
+ // WorkManager can only schedule when the user data directories are unencrypted (after
+ // the user has entered their lock password.
+ DomainVerificationUtils.schedulePeriodicCheckUnlocked(WorkManager.getInstance(this))
+ }
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/BaseDomainVerificationReceiver.kt b/packages/StatementService/src/com/android/statementservice/domain/BaseDomainVerificationReceiver.kt
new file mode 100644
index 000000000000..de41486d1996
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/BaseDomainVerificationReceiver.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.statementservice.domain
+
+import android.content.BroadcastReceiver
+import android.util.Log
+import androidx.work.Constraints
+import androidx.work.NetworkType
+
+abstract class BaseDomainVerificationReceiver : BroadcastReceiver() {
+
+ companion object {
+ const val DEBUG = false
+ }
+
+ protected abstract val tag: String
+
+ protected val networkConstraints = Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.CONNECTED)
+ .build()
+
+ protected fun debugLog(block: () -> String) {
+ if (DEBUG) {
+ Log.d(tag, block())
+ }
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/BootCompletedReceiver.kt b/packages/StatementService/src/com/android/statementservice/domain/BootCompletedReceiver.kt
new file mode 100644
index 000000000000..7b5da832b9d7
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/BootCompletedReceiver.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import androidx.work.Constraints
+import androidx.work.ExistingWorkPolicy
+import androidx.work.NetworkType
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkManager
+import com.android.statementservice.domain.worker.RetryRequestWorker
+
+/**
+ * Handles [Intent.ACTION_BOOT_COMPLETED] to schedule recurring maintenance [WorkManager] tasks and
+ * run a one-time retry request to attempt to verify domains that may have failed or been added
+ * since last device reboot.
+ *
+ * Note that this requires the user to have unlocked the device, since [WorkManager] cannot handle
+ * the encrypted user data directories.
+ */
+class BootCompletedReceiver : BroadcastReceiver() {
+
+ companion object {
+ private const val PACKAGE_BOOT_REQUEST_KEY = "package_boot_request"
+ }
+
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action != Intent.ACTION_BOOT_COMPLETED) return
+ val workManager = WorkManager.getInstance(context)
+ DomainVerificationUtils.schedulePeriodicCheckUnlocked(workManager)
+ workManager.beginUniqueWork(
+ PACKAGE_BOOT_REQUEST_KEY,
+ ExistingWorkPolicy.REPLACE,
+ OneTimeWorkRequestBuilder<RetryRequestWorker>()
+ .setConstraints(
+ Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.CONNECTED)
+ .build()
+ )
+ .build()
+ ).enqueue()
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt
new file mode 100644
index 000000000000..0ec8ed3416b8
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import androidx.work.ExistingWorkPolicy
+import androidx.work.WorkManager
+import com.android.statementservice.domain.worker.CollectV1Worker
+import com.android.statementservice.domain.worker.SingleV1RequestWorker
+
+/**
+ * Receiver for V1 API. Separated so that the receiver permission can be declared for only the
+ * v1 and v2 permissions individually, exactly matching the intended usage.
+ */
+class DomainVerificationReceiverV1 : BaseDomainVerificationReceiver() {
+
+ companion object {
+ private const val ENABLE_V1 = true
+ private const val PACKAGE_WORK_PREFIX_V1 = "package_request_v1-"
+ }
+
+ override val tag = DomainVerificationReceiverV1::class.java.simpleName
+
+ override fun onReceive(context: Context, intent: Intent) {
+ when (intent.action) {
+ Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION ->
+ scheduleUnlockedV1(context, intent)
+ else -> debugLog { "Received invalid broadcast: $intent" }
+ }
+ }
+
+ private fun scheduleUnlockedV1(context: Context, intent: Intent) {
+ if (!ENABLE_V1) {
+ return
+ }
+
+ val verificationId =
+ intent.getIntExtra(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID, -1)
+ val hosts =
+ (intent.getStringExtra(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS) ?: return)
+ .split(" ")
+ val packageName =
+ intent.getStringExtra(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME)
+ ?: return
+
+ debugLog { "Attempting v1 verification for $packageName" }
+
+ val workRequests = hosts.map {
+ SingleV1RequestWorker.buildRequest(packageName, it) {
+ setConstraints(networkConstraints)
+ }
+ }
+
+ WorkManager.getInstance(context)
+ .beginUniqueWork(
+ "$PACKAGE_WORK_PREFIX_V1$packageName",
+ ExistingWorkPolicy.REPLACE,
+ workRequests
+ )
+ .then(CollectV1Worker.buildRequest(verificationId, packageName))
+ .enqueue()
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV2.kt b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV2.kt
new file mode 100644
index 000000000000..24e0f50873c6
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV2.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.verify.domain.DomainVerificationManager
+import android.content.pm.verify.domain.DomainVerificationRequest
+import android.os.UserManager
+import androidx.work.BackoffPolicy
+import androidx.work.ExistingWorkPolicy
+import androidx.work.WorkManager
+import com.android.statementservice.domain.worker.SingleV2RequestWorker
+import com.android.statementservice.utils.component1
+import com.android.statementservice.utils.component2
+import com.android.statementservice.utils.component3
+
+import java.time.Duration
+
+/**
+ * Handles [DomainVerificationRequest]s from the system, which indicates a package on the device
+ * has domains which require verification against a server side assetlinks.json file, allowing the
+ * app to resolve web [Intent]s.
+ *
+ * This will delegate to v1 or v2 depending on the received broadcast and which components are
+ * enabled. See [DomainVerificationManager] for the full API.
+ */
+open class DomainVerificationReceiverV2 : BaseDomainVerificationReceiver() {
+
+ companion object {
+
+ private const val ENABLE_V2 = true
+
+ /**
+ * Toggle to always re-verify packages that this receiver is notified of. This means on
+ * every package change, even previously successful requests are re-sent. Generally only
+ * for debugging.
+ */
+ @Suppress("SimplifyBooleanWithConstants")
+ private const val ALWAYS_VERIFY = false || DEBUG
+
+ private const val PACKAGE_WORK_PREFIX_V2 = "package_request_v2-"
+ }
+
+ override val tag = DomainVerificationReceiverV2::class.java.simpleName
+
+ override fun onReceive(context: Context, intent: Intent) {
+ when (intent.action) {
+ Intent.ACTION_DOMAINS_NEED_VERIFICATION -> {
+ // If the user isn't unlocked yet, the request will be ignored, as WorkManager
+ // cannot schedule workers when the user data directories are encrypted.
+ if (context.getSystemService(UserManager::class.java)?.isUserUnlocked == true) {
+ scheduleUnlockedV2(context, intent)
+ }
+ }
+ else -> debugLog { "Received invalid broadcast: $intent" }
+ }
+ }
+
+ private fun scheduleUnlockedV2(context: Context, intent: Intent) {
+ if (!ENABLE_V2) {
+ return
+ }
+
+ val manager = context.getSystemService(DomainVerificationManager::class.java) ?: return
+ val workManager = WorkManager.getInstance(context)
+
+ val request = intent.getParcelableExtra<DomainVerificationRequest>(
+ DomainVerificationManager.EXTRA_VERIFICATION_REQUEST
+ ) ?: return
+
+ debugLog { "Attempting v2 verification for ${request.packageNames}" }
+
+ request.packageNames.forEach { packageName ->
+ val (domainSetId, _, hostToStateMap) = manager.getDomainVerificationInfo(packageName)
+ ?: return@forEach
+
+ val workRequests = hostToStateMap
+ .filterValues {
+ // TODO(b/159952358): Should we support re-query? There's no good way to
+ // signal to an AOSP implementation from an entity's website about when
+ // to re-query, unless it's just done on each update.
+ // AOSP implementation does not support re-query
+ ALWAYS_VERIFY || VerifyStatus.shouldRetry(it)
+ }
+ .map { (host, _) ->
+ SingleV2RequestWorker.buildRequest(domainSetId, packageName, host) {
+ setConstraints(networkConstraints)
+ setBackoffCriteria(BackoffPolicy.EXPONENTIAL, Duration.ofHours(1))
+ }
+ }
+
+ if (workRequests.isNotEmpty()) {
+ workManager.beginUniqueWork(
+ "$PACKAGE_WORK_PREFIX_V2$packageName",
+ ExistingWorkPolicy.REPLACE, workRequests
+ )
+ .enqueue()
+ }
+ }
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationUtils.kt b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationUtils.kt
new file mode 100644
index 000000000000..694424822b30
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationUtils.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain
+
+import androidx.work.Constraints
+import androidx.work.ExistingPeriodicWorkPolicy
+import androidx.work.NetworkType
+import androidx.work.PeriodicWorkRequestBuilder
+import androidx.work.WorkManager
+import com.android.statementservice.domain.worker.RetryRequestWorker
+import java.time.Duration
+
+object DomainVerificationUtils {
+
+ private const val PERIODIC_SHORT_ID = "retry_short"
+ private const val PERIODIC_SHORT_HOURS = 24L
+ private const val PERIODIC_LONG_ID = "retry_long"
+ private const val PERIODIC_LONG_HOURS = 72L
+
+ /**
+ * In a majority of cases, the initial requests will be enough to verify domains, since they
+ * are also restricted to [NetworkType.CONNECTED], but for cases where they aren't sufficient,
+ * attempts are also made on a periodic basis.
+ *
+ * Once per 24 hours, a check of all packages is done with [NetworkType.CONNECTED]. To avoid
+ * cases where a proxy or other unusual device configuration prevents [WorkManager] from
+ * running, also schedule a 3 day task without constraints which will force the check to run.
+ *
+ * The actual logic may be skipped if a request was previously run successfully or there are no
+ * more domains that need verifying.
+ */
+ fun schedulePeriodicCheckUnlocked(workManager: WorkManager) {
+ workManager.apply {
+ PeriodicWorkRequestBuilder<RetryRequestWorker>(Duration.ofHours(PERIODIC_SHORT_HOURS))
+ .setConstraints(
+ Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.CONNECTED)
+ .setRequiresDeviceIdle(true)
+ .build()
+ )
+ .build()
+ .let {
+ enqueueUniquePeriodicWork(
+ PERIODIC_SHORT_ID,
+ ExistingPeriodicWorkPolicy.KEEP, it
+ )
+ }
+ PeriodicWorkRequestBuilder<RetryRequestWorker>(Duration.ofDays(PERIODIC_LONG_HOURS))
+ .setConstraints(
+ Constraints.Builder()
+ .setRequiresDeviceIdle(true)
+ .build()
+ )
+ .build()
+ .let {
+ enqueueUniquePeriodicWork(
+ PERIODIC_LONG_ID,
+ ExistingPeriodicWorkPolicy.KEEP, it
+ )
+ }
+ }
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/DomainVerifier.kt b/packages/StatementService/src/com/android/statementservice/domain/DomainVerifier.kt
new file mode 100644
index 000000000000..29f844fb1a5d
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/DomainVerifier.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain
+
+import android.content.Context
+import android.content.pm.verify.domain.DomainVerificationManager
+import android.net.Network
+import android.util.Log
+import androidx.collection.LruCache
+import com.android.statementservice.network.retriever.StatementRetriever
+import com.android.statementservice.retriever.AbstractAsset
+import com.android.statementservice.retriever.AbstractAssetMatcher
+import com.android.statementservice.utils.Result
+import com.android.statementservice.utils.StatementUtils
+import com.android.statementservice.utils.component1
+import com.android.statementservice.utils.component2
+import com.android.statementservice.utils.component3
+import java.net.HttpURLConnection
+import java.util.Optional
+import java.util.UUID
+
+private typealias WorkResult = androidx.work.ListenableWorker.Result
+
+class DomainVerifier private constructor(
+ private val appContext: Context,
+ private val manager: DomainVerificationManager
+) {
+ companion object {
+ private val TAG = DomainVerifier::class.java.simpleName
+ private const val DEBUG = false
+
+ private var singleton: DomainVerifier? = null
+
+ fun getInstance(context: Context) = when {
+ singleton != null -> singleton!!
+ else -> synchronized(this) {
+ if (singleton == null) {
+ val appContext = context.applicationContext
+ val manager =
+ appContext.getSystemService(DomainVerificationManager::class.java)!!
+ singleton = DomainVerifier(appContext, manager)
+ }
+ singleton!!
+ }
+ }
+ }
+
+ private val retriever = StatementRetriever()
+
+ private val targetAssetCache = AssetLruCache()
+
+ fun collectHosts(packageNames: Iterable<String>): Iterable<Triple<UUID, String, String>> {
+ return packageNames.mapNotNull { packageName ->
+ val (domainSetId, _, hostToStateMap) = try {
+ manager.getDomainVerificationInfo(packageName)
+ } catch (ignored: Exception) {
+ // Package disappeared, assume it will be rescheduled if the package reappears
+ null
+ } ?: return@mapNotNull null
+
+ val hostsToRetry = hostToStateMap
+ .filterValues(VerifyStatus::shouldRetry)
+ .takeIf { it.isNotEmpty() }
+ ?.map { it.key }
+ ?: return@mapNotNull null
+
+ hostsToRetry.map { Triple(domainSetId, packageName, it) }
+ }
+ .flatten()
+ }
+
+ suspend fun verifyHost(
+ host: String,
+ packageName: String,
+ network: Network? = null
+ ): Pair<WorkResult, VerifyStatus> {
+ val assetMatcher = synchronized(targetAssetCache) { targetAssetCache[packageName] }
+ .takeIf { it!!.isPresent }
+ ?: return WorkResult.failure() to VerifyStatus.FAILURE_PACKAGE_MANAGER
+ return verifyHost(host, assetMatcher.get(), network)
+ }
+
+ private suspend fun verifyHost(
+ host: String,
+ assetMatcher: AbstractAssetMatcher,
+ network: Network? = null
+ ): Pair<WorkResult, VerifyStatus> {
+ var exception: Exception? = null
+ val resultAndStatus = try {
+ val sourceAsset = StatementUtils.createWebAssetString(host)
+ .let(AbstractAsset::create)
+ val result = retriever.retrieve(sourceAsset, network)
+ ?: return WorkResult.success() to VerifyStatus.FAILURE_UNKNOWN
+ when (result.responseCode) {
+ HttpURLConnection.HTTP_MOVED_PERM,
+ HttpURLConnection.HTTP_MOVED_TEMP -> {
+ WorkResult.failure() to VerifyStatus.FAILURE_REDIRECT
+ }
+ else -> {
+ val isVerified = result.statements.any { statement ->
+ (StatementUtils.RELATION.matches(statement.relation) &&
+ assetMatcher.matches(statement.target))
+ }
+
+ if (isVerified) {
+ WorkResult.success() to VerifyStatus.SUCCESS
+ } else {
+ WorkResult.failure() to VerifyStatus.FAILURE_REJECTED_BY_SERVER
+ }
+ }
+ }
+ } catch (e: Exception) {
+ exception = e
+ WorkResult.retry() to VerifyStatus.FAILURE_UNKNOWN
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "Verifying $host: ${resultAndStatus.second}", exception)
+ }
+
+ return resultAndStatus
+ }
+
+ private inner class AssetLruCache : LruCache<String, Optional<AbstractAssetMatcher>>(50) {
+ override fun create(packageName: String) =
+ StatementUtils.getCertFingerprintsFromPackageManager(appContext, packageName)
+ .let { (it as? Result.Success)?.value }
+ ?.let { StatementUtils.createAndroidAsset(packageName, it) }
+ ?.let(AbstractAssetMatcher::createMatcher)
+ .let { Optional.ofNullable(it) }
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/VerifyStatus.kt b/packages/StatementService/src/com/android/statementservice/domain/VerifyStatus.kt
new file mode 100644
index 000000000000..2193ec542238
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/VerifyStatus.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain
+
+import android.content.pm.verify.domain.DomainVerificationInfo
+import android.content.pm.verify.domain.DomainVerificationManager
+
+/**
+ * Wraps known [DomainVerificationManager] status codes so that they can be used in a when
+ * statement. Unknown codes are coerced to [VerifyStatus.UNKNOWN] and should be treated as
+ * unverified.
+ *
+ * Also includes error codes specific to this implementation of the domain verification agent.
+ * These must be stable across all versions, as codes are persisted to disk. They do not
+ * technically have to be stable across different device factory resets, since they will be reset
+ * once the apps are re-initialized, but easier to keep them unique forever.
+ */
+enum class VerifyStatus(val value: Int) {
+ NO_RESPONSE(DomainVerificationInfo.STATE_NO_RESPONSE),
+ SUCCESS(DomainVerificationInfo.STATE_SUCCESS),
+
+ UNKNOWN(DomainVerificationInfo.STATE_FIRST_VERIFIER_DEFINED),
+ FAILURE_LEGACY_UNSUPPORTED_WILDCARD(DomainVerificationInfo.STATE_FIRST_VERIFIER_DEFINED + 1),
+ FAILURE_REJECTED_BY_SERVER(DomainVerificationInfo.STATE_FIRST_VERIFIER_DEFINED + 2),
+ FAILURE_TIMEOUT(DomainVerificationInfo.STATE_FIRST_VERIFIER_DEFINED + 3),
+ FAILURE_UNKNOWN(DomainVerificationInfo.STATE_FIRST_VERIFIER_DEFINED + 4),
+ FAILURE_REDIRECT(DomainVerificationInfo.STATE_FIRST_VERIFIER_DEFINED + 5),
+
+ // Failed to retrieve signature information from PackageManager
+ FAILURE_PACKAGE_MANAGER(DomainVerificationInfo.STATE_FIRST_VERIFIER_DEFINED + 6);
+
+ companion object {
+ fun shouldRetry(state: Int): Boolean {
+ if (state == DomainVerificationInfo.STATE_UNMODIFIABLE) {
+ return false
+ }
+
+ val status = values().find { it.value == state } ?: return true
+ return when (status) {
+ SUCCESS,
+ FAILURE_LEGACY_UNSUPPORTED_WILDCARD,
+ FAILURE_REJECTED_BY_SERVER,
+ FAILURE_PACKAGE_MANAGER,
+ UNKNOWN -> false
+ NO_RESPONSE,
+ FAILURE_TIMEOUT,
+ FAILURE_UNKNOWN,
+ FAILURE_REDIRECT -> true
+ }
+ }
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/BaseRequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/BaseRequestWorker.kt
new file mode 100644
index 000000000000..a17f9c9186ff
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/BaseRequestWorker.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain.worker
+
+import android.content.Context
+import android.content.pm.verify.domain.DomainVerificationManager
+import androidx.work.CoroutineWorker
+import androidx.work.WorkerParameters
+import com.android.statementservice.domain.DomainVerifier
+
+abstract class BaseRequestWorker(
+ protected val appContext: Context,
+ protected val params: WorkerParameters
+) : CoroutineWorker(appContext, params) {
+
+ protected val verificationManager =
+ appContext.getSystemService(DomainVerificationManager::class.java)!!
+
+ protected val verifier = DomainVerifier.getInstance(appContext)
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt
new file mode 100644
index 000000000000..3a3aea9288cd
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain.worker
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.util.Log
+import androidx.work.Data
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkerParameters
+import com.android.statementservice.utils.AndroidUtils
+import kotlinx.coroutines.coroutineScope
+
+class CollectV1Worker(appContext: Context, params: WorkerParameters) :
+ BaseRequestWorker(appContext, params) {
+
+ companion object {
+ private val TAG = CollectV1Worker::class.java.simpleName
+ private const val DEBUG = false
+
+ private const val VERIFICATION_ID_KEY = "verificationId"
+ private const val PACKAGE_NAME_KEY = "packageName"
+
+ fun buildRequest(verificationId: Int, packageName: String) =
+ OneTimeWorkRequestBuilder<CollectV1Worker>()
+ .setInputData(
+ Data.Builder()
+ .putInt(VERIFICATION_ID_KEY, verificationId)
+ .apply {
+ if (DEBUG) {
+ putString(PACKAGE_NAME_KEY, packageName)
+ }
+ }
+ .build()
+ )
+ .build()
+ }
+
+ override suspend fun doWork() = coroutineScope {
+ if (!AndroidUtils.isReceiverV1Enabled(appContext)) {
+ return@coroutineScope Result.success()
+ }
+
+ val inputData = params.inputData
+ val verificationId = inputData.getInt(VERIFICATION_ID_KEY, -1)
+ val successfulHosts = mutableListOf<String>()
+ val failedHosts = mutableListOf<String>()
+ inputData.keyValueMap.entries.forEach { (key, _) ->
+ when {
+ key.startsWith(SingleV1RequestWorker.HOST_SUCCESS_PREFIX) ->
+ successfulHosts += key.removePrefix(SingleV1RequestWorker.HOST_SUCCESS_PREFIX)
+ key.startsWith(SingleV1RequestWorker.HOST_FAILURE_PREFIX) ->
+ failedHosts += key.removePrefix(SingleV1RequestWorker.HOST_FAILURE_PREFIX)
+ }
+ }
+
+ if (DEBUG) {
+ val packageName = inputData.getString(PACKAGE_NAME_KEY)
+ Log.d(
+ TAG, "Domain verification v1 request for $packageName: " +
+ "success = $successfulHosts, failed = $failedHosts"
+ )
+ }
+
+ val resultCode = if (failedHosts.isEmpty()) {
+ PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS
+ } else {
+ PackageManager.INTENT_FILTER_VERIFICATION_FAILURE
+ }
+
+ appContext.packageManager.verifyIntentFilter(verificationId, resultCode, failedHosts)
+
+ Result.success()
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/RetryRequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/RetryRequestWorker.kt
new file mode 100644
index 000000000000..61ab2c264e6a
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/RetryRequestWorker.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain.worker
+
+import android.content.Context
+import androidx.work.NetworkType
+import androidx.work.WorkerParameters
+import com.android.statementservice.domain.VerifyStatus
+import com.android.statementservice.utils.AndroidUtils
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.isActive
+import java.util.UUID
+
+/**
+ * Scheduled every 24 hours with [NetworkType.CONNECTED] and every 72 hours without any constraints
+ * to retry all domains for all packages with a failing error code.
+ */
+class RetryRequestWorker(
+ appContext: Context,
+ params: WorkerParameters
+) : BaseRequestWorker(appContext, params) {
+
+ data class VerifyResult(val domainSetId: UUID, val host: String, val status: VerifyStatus)
+
+ override suspend fun doWork() = coroutineScope {
+ if (!AndroidUtils.isReceiverV2Enabled(appContext)) {
+ return@coroutineScope Result.success()
+ }
+
+ val packageNames = verificationManager.queryValidVerificationPackageNames()
+
+ verifier.collectHosts(packageNames)
+ .map { (domainSetId, packageName, host) ->
+ async {
+ if (isActive && !isStopped) {
+ val (_, status) = verifier.verifyHost(host, packageName, params.network)
+ VerifyResult(domainSetId, host, status)
+ } else {
+ // If the job gets cancelled, stop the remaining hosts, but continue the
+ // job to commit the results for hosts that were already requested.
+ null
+ }
+ }
+ }
+ .awaitAll()
+ .filterNotNull() // TODO(b/159952358): Fast fail packages which can't be retrieved.
+ .groupBy { it.domainSetId }
+ .forEach { (domainSetId, resultsById) ->
+ resultsById.groupBy { it.status }
+ .mapValues { it.value.map(VerifyResult::host).toSet() }
+ .forEach { (status, hosts) ->
+ verificationManager.setDomainVerificationStatus(
+ domainSetId,
+ hosts,
+ status.value
+ )
+ }
+ }
+
+ // Succeed regardless of results since this retry is best effort and not required
+ Result.success()
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt
new file mode 100644
index 000000000000..cd8a18218004
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain.worker
+
+import android.content.Context
+import android.util.Log
+import androidx.work.Data
+import androidx.work.OneTimeWorkRequest
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkerParameters
+import com.android.statementservice.utils.AndroidUtils
+import kotlinx.coroutines.coroutineScope
+
+class SingleV1RequestWorker(appContext: Context, params: WorkerParameters) :
+ BaseRequestWorker(appContext, params) {
+
+ companion object {
+ private val TAG = SingleV1RequestWorker::class.java.simpleName
+ private const val DEBUG = false
+
+ private const val PACKAGE_NAME_KEY = "packageName"
+ private const val HOST_KEY = "host"
+ const val HOST_SUCCESS_PREFIX = "hostSuccess:"
+ const val HOST_FAILURE_PREFIX = "hostFailure:"
+
+ fun buildRequest(
+ packageName: String,
+ host: String,
+ block: OneTimeWorkRequest.Builder.() -> Unit = {}
+ ) = OneTimeWorkRequestBuilder<SingleV1RequestWorker>()
+ .setInputData(
+ Data.Builder()
+ .putString(PACKAGE_NAME_KEY, packageName)
+ .putString(HOST_KEY, host)
+ .build()
+ )
+ .apply(block)
+ .build()
+ }
+
+ override suspend fun doWork() = coroutineScope {
+ if (!AndroidUtils.isReceiverV1Enabled(appContext)) {
+ return@coroutineScope Result.success()
+ }
+
+ val packageName = params.inputData.getString(PACKAGE_NAME_KEY)!!
+ val host = params.inputData.getString(HOST_KEY)!!
+
+ val (result, status) = verifier.verifyHost(host, packageName, params.network)
+
+ if (DEBUG) {
+ Log.d(
+ TAG, "Domain verification v1 request for $packageName: " +
+ "host = $host, status = $status"
+ )
+ }
+
+ // Coerce failure results into success so that final collection task gets a chance to run
+ when (result) {
+ is Result.Success -> Result.success(
+ Data.Builder()
+ .putInt("$HOST_SUCCESS_PREFIX$host", status.value)
+ .build()
+ )
+ is Result.Failure -> Result.success(
+ Data.Builder()
+ .putInt("$HOST_FAILURE_PREFIX$host", status.value)
+ .build()
+ )
+ else -> result
+ }
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV2RequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV2RequestWorker.kt
new file mode 100644
index 000000000000..562b132d36d6
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV2RequestWorker.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 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.statementservice.domain.worker
+
+import android.content.Context
+import androidx.work.Data
+import androidx.work.OneTimeWorkRequest
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkerParameters
+import com.android.statementservice.utils.AndroidUtils
+import kotlinx.coroutines.coroutineScope
+import java.util.UUID
+
+class SingleV2RequestWorker(appContext: Context, params: WorkerParameters) :
+ BaseRequestWorker(appContext, params) {
+
+ companion object {
+ private const val DOMAIN_SET_ID_KEY = "domainSetId"
+ private const val PACKAGE_NAME_KEY = "packageName"
+ private const val HOST_KEY = "host"
+
+ fun buildRequest(
+ domainSetId: UUID,
+ packageName: String,
+ host: String,
+ block: OneTimeWorkRequest.Builder.() -> Unit = {}
+ ) = OneTimeWorkRequestBuilder<SingleV2RequestWorker>()
+ .setInputData(
+ Data.Builder()
+ .putString(DOMAIN_SET_ID_KEY, domainSetId.toString())
+ .putString(PACKAGE_NAME_KEY, packageName)
+ .putString(HOST_KEY, host)
+ .build()
+ )
+ .apply(block)
+ .build()
+ }
+
+ override suspend fun doWork() = coroutineScope {
+ if (!AndroidUtils.isReceiverV2Enabled(appContext)) {
+ return@coroutineScope Result.success()
+ }
+
+ val domainSetId = params.inputData.getString(DOMAIN_SET_ID_KEY)!!.let(UUID::fromString)
+ val packageName = params.inputData.getString(PACKAGE_NAME_KEY)!!
+ val host = params.inputData.getString(HOST_KEY)!!
+
+ val (result, status) = verifier.verifyHost(host, packageName, params.network)
+
+ verificationManager.setDomainVerificationStatus(domainSetId, setOf(host), status.value)
+
+ result
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/network/retriever/StatementParser.kt b/packages/StatementService/src/com/android/statementservice/network/retriever/StatementParser.kt
new file mode 100644
index 000000000000..455e8085af50
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/network/retriever/StatementParser.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 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.statementservice.network.retriever
+
+import android.util.JsonReader
+import com.android.statementservice.retriever.AbstractAsset
+import com.android.statementservice.retriever.AssetFactory
+import com.android.statementservice.retriever.JsonParser
+import com.android.statementservice.retriever.Relation
+import com.android.statementservice.retriever.Statement
+import com.android.statementservice.utils.Result
+import com.android.statementservice.utils.StatementUtils
+import java.io.StringReader
+import java.util.ArrayList
+import com.android.statementservice.retriever.WebAsset
+import com.android.statementservice.retriever.AndroidAppAsset
+
+/**
+ * Parses JSON from the Digital Asset Links specification. For examples, see [WebAsset],
+ * [AndroidAppAsset], and [Statement].
+ */
+object StatementParser {
+
+ private const val FIELD_NOT_STRING_FORMAT_STRING = "Expected %s to be string."
+ private const val FIELD_NOT_ARRAY_FORMAT_STRING = "Expected %s to be array."
+
+ /**
+ * Parses a JSON array of statements.
+ */
+ fun parseStatementList(statementList: String, source: AbstractAsset): Result<ParsedStatement> {
+ val statements: MutableList<Statement> = ArrayList()
+ val delegates: MutableList<String> = ArrayList()
+ StringReader(statementList).use { stringReader ->
+ JsonReader(stringReader).use { reader ->
+ reader.isLenient = false
+ reader.beginArray()
+ while (reader.hasNext()) {
+ val result = parseOneStatement(reader, source)
+ if (result is Result.Failure) {
+ continue
+ }
+ result as Result.Success
+ statements.addAll(result.value.statements)
+ delegates.addAll(result.value.delegates)
+ }
+ reader.endArray()
+ }
+ }
+ return Result.Success(ParsedStatement(statements, delegates))
+ }
+
+ /**
+ * Parses a single JSON statement.
+ */
+ fun parseStatement(statementString: String, source: AbstractAsset) =
+ StringReader(statementString).use { stringReader ->
+ JsonReader(stringReader).use { reader ->
+ reader.isLenient = false
+ parseOneStatement(reader, source)
+ }
+ }
+
+ /**
+ * Parses a single JSON statement. This method guarantees that exactly one JSON object
+ * will be consumed.
+ */
+ private fun parseOneStatement(
+ reader: JsonReader,
+ source: AbstractAsset
+ ): Result<ParsedStatement> {
+ val statement = JsonParser.parse(reader)
+ val delegate = statement.optString(StatementUtils.DELEGATE_FIELD_DELEGATE)
+ if (!delegate.isNullOrEmpty()) {
+ return Result.Success(ParsedStatement(emptyList(), listOfNotNull(delegate)))
+ }
+
+ val targetObject = statement.optJSONObject(StatementUtils.ASSET_DESCRIPTOR_FIELD_TARGET)
+ ?: return Result.Failure(
+ FIELD_NOT_STRING_FORMAT_STRING.format(StatementUtils.ASSET_DESCRIPTOR_FIELD_TARGET)
+ )
+ val relations = statement.optJSONArray(StatementUtils.ASSET_DESCRIPTOR_FIELD_RELATION)
+ ?: return Result.Failure(
+ FIELD_NOT_ARRAY_FORMAT_STRING.format(StatementUtils.ASSET_DESCRIPTOR_FIELD_RELATION)
+ )
+ val target = AssetFactory.create(targetObject)
+
+ val statements = (0 until relations.length())
+ .map { relations.getString(it) }
+ .map(Relation::create)
+ .map { Statement.create(source, target, it) }
+ return Result.Success(ParsedStatement(statements, listOfNotNull(delegate)))
+ }
+
+ data class ParsedStatement(val statements: List<Statement>, val delegates: List<String>)
+}
diff --git a/packages/StatementService/src/com/android/statementservice/network/retriever/StatementRetriever.kt b/packages/StatementService/src/com/android/statementservice/network/retriever/StatementRetriever.kt
new file mode 100644
index 000000000000..c27a26ad0995
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/network/retriever/StatementRetriever.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 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.statementservice.network.retriever
+
+import android.content.Intent
+import android.net.Network
+import com.android.statementservice.retriever.AbstractAsset
+import com.android.statementservice.retriever.AndroidAppAsset
+import com.android.statementservice.retriever.Statement
+import com.android.statementservice.retriever.WebAsset
+import com.android.statementservice.utils.StatementUtils.tryOrNull
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.withContext
+import java.net.URL
+
+/**
+ * Retrieves the JSON configured at a given domain that's compliant with the Digital Asset Links
+ * specification, returning the list of statements which serve as assertions by the web server as
+ * to what other assets it can be connected with.
+ *
+ * Relevant to this app, it allows the website to report which Android app package and signature
+ * digest has been approved by the website owner, which considers them as the same author and safe
+ * to automatically delegate web [Intent]s to.
+ *
+ * The relevant data classes are [WebAsset], [AndroidAppAsset], and [Statement].
+ */
+class StatementRetriever {
+
+ companion object {
+ private const val HTTP_CONNECTION_TIMEOUT_MILLIS = 5000
+ private const val HTTP_CONTENT_SIZE_LIMIT_IN_BYTES = (1024 * 1024).toLong()
+ private const val MAX_INCLUDE_LEVEL = 1
+ private const val WELL_KNOWN_STATEMENT_PATH = "/.well-known/assetlinks.json"
+ }
+
+ private val fetcher = UrlFetcher()
+
+ data class Result(
+ val statements: List<Statement>,
+ val responseCode: Int?
+ ) {
+ companion object {
+ val EMPTY = Result(emptyList(), null)
+ }
+
+ constructor(statements: List<Statement>, webResult: UrlFetcher.Response) : this(
+ statements,
+ webResult.responseCode
+ )
+ }
+
+ suspend fun retrieve(source: AbstractAsset, network: Network? = null) = when (source) {
+ // TODO:(b/171219506): Does this have to be implemented?
+ is AndroidAppAsset -> null
+ is WebAsset -> retrieveFromWeb(source, network)
+ else -> null
+ }
+
+ private suspend fun retrieveFromWeb(asset: WebAsset, network: Network? = null): Result? {
+ val url = computeAssociationJsonUrl(asset) ?: return null
+ return retrieve(url, MAX_INCLUDE_LEVEL, asset, network)
+ }
+
+ private fun computeAssociationJsonUrl(asset: WebAsset) = tryOrNull {
+ URL(asset.scheme, asset.domain, asset.port, WELL_KNOWN_STATEMENT_PATH).toExternalForm()
+ }
+
+ private suspend fun retrieve(
+ urlString: String,
+ maxIncludeLevel: Int,
+ source: AbstractAsset,
+ network: Network? = null
+ ): Result {
+ if (maxIncludeLevel < 0) {
+ return Result.EMPTY
+ }
+
+ return withContext(Dispatchers.IO) {
+ val url = try {
+ @Suppress("BlockingMethodInNonBlockingContext")
+ URL(urlString)
+ } catch (ignored: Exception) {
+ return@withContext Result.EMPTY
+ }
+
+ val webResponse = fetcher.fetch(
+ url = url,
+ connectionTimeoutMillis = HTTP_CONNECTION_TIMEOUT_MILLIS,
+ fileSizeLimit = HTTP_CONTENT_SIZE_LIMIT_IN_BYTES,
+ network
+ ).successValueOrNull() ?: return@withContext Result.EMPTY
+
+ val content = webResponse.content ?: return@withContext Result(emptyList(), webResponse)
+ val (statements, delegates) = StatementParser.parseStatementList(content, source)
+ .successValueOrNull() ?: return@withContext Result(emptyList(), webResponse)
+
+ val delegatedStatements = delegates
+ .map { async { retrieve(it, maxIncludeLevel - 1, source).statements } }
+ .awaitAll()
+ .flatten()
+
+ Result(statements + delegatedStatements, webResponse)
+ }
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/network/retriever/UrlFetcher.kt b/packages/StatementService/src/com/android/statementservice/network/retriever/UrlFetcher.kt
new file mode 100644
index 000000000000..5c1f5e09b957
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/network/retriever/UrlFetcher.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 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.statementservice.network.retriever
+
+import android.net.Network
+import android.net.TrafficStats
+import android.util.Log
+import com.android.statementservice.utils.Result
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.withContext
+import java.net.HttpURLConnection
+import java.net.URL
+import java.nio.charset.Charset
+import javax.net.ssl.HttpsURLConnection
+
+class UrlFetcher {
+
+ companion object {
+ private val TAG = UrlFetcher::class.java.simpleName
+ }
+
+ suspend fun fetch(
+ url: URL,
+ connectionTimeoutMillis: Int,
+ fileSizeLimit: Long,
+ network: Network? = null
+ ) = withContext(Dispatchers.IO) {
+ TrafficStats.setThreadStatsTag(Thread.currentThread().id.toInt())
+ @Suppress("BlockingMethodInNonBlockingContext")
+ val connection =
+ ((network?.openConnection(url) ?: url.openConnection()) as HttpsURLConnection)
+ try {
+ connection.apply {
+ connectTimeout = connectionTimeoutMillis
+ readTimeout = connectionTimeoutMillis
+ useCaches = true
+ instanceFollowRedirects = false
+ addRequestProperty("Cache-Control", "max-stale=60")
+ }
+ val responseCode = connection.responseCode
+ when {
+ responseCode != HttpURLConnection.HTTP_OK -> {
+ Log.w(TAG, "The responses code is not 200 but $responseCode")
+ Result.Success(Response(responseCode))
+ }
+ connection.contentLength > fileSizeLimit -> {
+ Log.w(TAG, "The content size of the url is larger than $fileSizeLimit")
+ Result.Success(Response(responseCode))
+ }
+ else -> {
+ val content = async {
+ connection.inputStream
+ .bufferedReader(Charset.forName("UTF-8"))
+ .readText()
+ }
+
+ Result.Success(Response(responseCode, content.await()))
+ }
+ }
+ } catch (ignored: Throwable) {
+ Result.Failure(ignored)
+ } finally {
+ connection.disconnect()
+ }
+ }
+
+ data class Response(
+ val responseCode: Int,
+ val content: String? = null
+ )
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java
index 8d6fd66db498..4834626edbb6 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java
@@ -81,6 +81,9 @@ public abstract class AbstractAsset {
/**
* If this is the source asset of a statement file, should the retriever follow
* any insecure (non-HTTPS) include statements made by the asset.
+ *
+ * TODO(b/171219506): Why would this be allowed? Can it be removed, even for web assets?
+ * Android doesn't even allow non-secure traffic by default.
*/
public abstract boolean followInsecureInclude();
}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
deleted file mode 100644
index fe9b99a0a976..000000000000
--- a/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice.retriever;
-
-import android.content.Context;
-import android.annotation.NonNull;
-
-import java.util.List;
-
-/**
- * Retrieves the statements made by assets. This class is the entry point of the package.
- * <p>
- * An asset is an identifiable and addressable online entity that typically
- * provides some service or content. Examples of assets are websites, Android
- * apps, Twitter feeds, and Plus Pages.
- * <p>
- * Ownership of an asset is defined by being able to control it and speak for it.
- * An asset owner may establish a relationship between the asset and another
- * asset by making a statement about an intended relationship between the two.
- * An example of a relationship is permission delegation. For example, the owner
- * of a website (the webmaster) may delegate the ability the handle URLs to a
- * particular mobile app. Relationships are considered public information.
- * <p>
- * A particular kind of relationship (like permission delegation) defines a binary
- * relation on assets. The relation is not symmetric or transitive, nor is it
- * antisymmetric or anti-transitive.
- * <p>
- * A statement S(r, a, b) is an assertion that the relation r holds for the
- * ordered pair of assets (a, b). For example, taking r = "delegates permission
- * to view user's location", a = New York Times mobile app,
- * b = nytimes.com website, S(r, a, b) would be an assertion that "the New York
- * Times mobile app delegates its ability to use the user's location to the
- * nytimes.com website".
- * <p>
- * A statement S(r, a, b) is considered <b>reliable</b> if we have confidence that
- * the statement is true; the exact criterion depends on the kind of statement,
- * since some kinds of statements may be true on their face whereas others may
- * require multiple parties to agree.
- * <p>
- * For example, to get the statements made by www.example.com use:
- * <pre>
- * result = retrieveStatements(AssetFactory.create(
- * "{\"namespace\": \"web\", \"site\": \"https://www.google.com\"}"))
- * </pre>
- * {@code result} will contain the statements and the expiration time of this result. The statements
- * are considered reliable until the expiration time.
- */
-public abstract class AbstractStatementRetriever {
-
- /**
- * Returns the statements made by the {@code source} asset with ttl.
- *
- * @throws AssociationServiceException if the asset namespace is not supported.
- */
- public abstract Result retrieveStatements(AbstractAsset source)
- throws AssociationServiceException;
-
- /**
- * The retrieved statements and the expiration date.
- */
- public interface Result {
-
- /**
- * @return the retrieved statements.
- */
- @NonNull
- public List<Statement> getStatements();
-
- /**
- * @return the expiration time in millisecond.
- */
- public long getExpireMillis();
- }
-
- /**
- * Creates a new StatementRetriever that directly retrieves statements from the asset.
- *
- * <p> For web assets, {@link AbstractStatementRetriever} will try to retrieve the statement
- * file from URL: {@code [webAsset.site]/.well-known/assetlinks.json"} where {@code
- * [webAsset.site]} is in the form {@code http{s}://[hostname]:[optional_port]}. The file
- * should contain one JSON array of statements.
- *
- * <p> For Android assets, {@link AbstractStatementRetriever} will try to retrieve the statement
- * from the AndroidManifest.xml. The developer should add a {@code meta-data} tag under
- * {@code application} tag where attribute {@code android:name} equals "associated_assets"
- * and {@code android:recourse} points to a string array resource. Each entry in the string
- * array should contain exactly one statement in JSON format. Note that this implementation
- * can only return statements made by installed apps.
- */
- public static AbstractStatementRetriever createDirectRetriever(Context context) {
- return new DirectStatementRetriever(new URLFetcher(),
- new AndroidPackageInfoFetcher(context));
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java
index 8ead90b88faf..14ca23243b4b 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java
@@ -16,6 +16,8 @@
package com.android.statementservice.retriever;
+import com.android.statementservice.utils.StatementUtils;
+
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -34,7 +36,8 @@ import java.util.Locale;
* "sha256_cert_fingerprints": ["[SHA256 fingerprint of signing cert]", "[additional cert]", ...] }
*
* <p>For example, { "namespace": "android_app", "package_name": "com.test.mytestapp",
- * "sha256_cert_fingerprints": ["24:D9:B4:57:A6:42:FB:E6:E5:B8:D6:9E:7B:2D:C2:D1:CB:D1:77:17:1D:7F:D4:A9:16:10:11:AB:92:B9:8F:3F"]
+ * "sha256_cert_fingerprints": ["24:D9:B4:57:A6:42:FB:E6:E5:B8:D6:9E:7B:2D:C2:D1:CB:D1:77:17:1D
+ * :7F:D4:A9:16:10:11:AB:92:B9:8F:3F"]
* }
*
* <p>Given a signed APK, Java 7's commandline keytool can compute the fingerprint using:
@@ -43,7 +46,7 @@ import java.util.Locale;
* <p>Each entry in "sha256_cert_fingerprints" is a colon-separated hex string (e.g. 14:6D:E9:...)
* representing the certificate SHA-256 fingerprint.
*/
-/* package private */ final class AndroidAppAsset extends AbstractAsset {
+public final class AndroidAppAsset extends AbstractAsset {
private static final String MISSING_FIELD_FORMAT_STRING = "Expected %s to be set.";
private static final String MISSING_APPCERTS_FORMAT_STRING =
@@ -65,9 +68,10 @@ import java.util.Locale;
public String toJson() {
AssetJsonWriter writer = new AssetJsonWriter();
- writer.writeFieldLower(Utils.NAMESPACE_FIELD, Utils.NAMESPACE_ANDROID_APP);
- writer.writeFieldLower(Utils.ANDROID_APP_ASSET_FIELD_PACKAGE_NAME, mPackageName);
- writer.writeArrayUpper(Utils.ANDROID_APP_ASSET_FIELD_CERT_FPS, mCertFingerprints);
+ writer.writeFieldLower(StatementUtils.NAMESPACE_FIELD,
+ StatementUtils.NAMESPACE_ANDROID_APP);
+ writer.writeFieldLower(StatementUtils.ANDROID_APP_ASSET_FIELD_PACKAGE_NAME, mPackageName);
+ writer.writeArrayUpper(StatementUtils.ANDROID_APP_ASSET_FIELD_CERT_FPS, mCertFingerprints);
return writer.closeAndGetString();
}
@@ -114,17 +118,17 @@ import java.util.Locale;
*/
public static AndroidAppAsset create(JSONObject asset)
throws AssociationServiceException {
- String packageName = asset.optString(Utils.ANDROID_APP_ASSET_FIELD_PACKAGE_NAME);
+ String packageName = asset.optString(StatementUtils.ANDROID_APP_ASSET_FIELD_PACKAGE_NAME);
if (packageName.equals("")) {
throw new AssociationServiceException(String.format(MISSING_FIELD_FORMAT_STRING,
- Utils.ANDROID_APP_ASSET_FIELD_PACKAGE_NAME));
+ StatementUtils.ANDROID_APP_ASSET_FIELD_PACKAGE_NAME));
}
- JSONArray certArray = asset.optJSONArray(Utils.ANDROID_APP_ASSET_FIELD_CERT_FPS);
+ JSONArray certArray = asset.optJSONArray(StatementUtils.ANDROID_APP_ASSET_FIELD_CERT_FPS);
if (certArray == null || certArray.length() == 0) {
throw new AssociationServiceException(
String.format(MISSING_APPCERTS_FORMAT_STRING,
- Utils.ANDROID_APP_ASSET_FIELD_CERT_FPS));
+ StatementUtils.ANDROID_APP_ASSET_FIELD_CERT_FPS));
}
List<String> certFingerprints = new ArrayList<>(certArray.length());
for (int i = 0; i < certArray.length(); i++) {
@@ -133,7 +137,7 @@ import java.util.Locale;
} catch (JSONException e) {
throw new AssociationServiceException(
String.format(APPCERT_NOT_STRING_FORMAT_STRING,
- Utils.ANDROID_APP_ASSET_FIELD_CERT_FPS));
+ StatementUtils.ANDROID_APP_ASSET_FIELD_CERT_FPS));
}
}
@@ -143,7 +147,7 @@ import java.util.Locale;
/**
* Creates a new AndroidAppAsset.
*
- * @param packageName the package name of the Android app.
+ * @param packageName the package name of the Android app.
* @param certFingerprints at least one of the Android app signing certificate sha-256
* fingerprint.
*/
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAssetMatcher.java b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAssetMatcher.java
index 8a9d838c7fed..45798faf91ff 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAssetMatcher.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAssetMatcher.java
@@ -23,7 +23,7 @@ import java.util.Set;
* Match assets that have the same 'package_name' field and have at least one common certificate
* fingerprint in 'sha256_cert_fingerprints' field.
*/
-/* package private */ final class AndroidAppAssetMatcher extends AbstractAssetMatcher {
+public final class AndroidAppAssetMatcher extends AbstractAssetMatcher {
private final AndroidAppAsset mQuery;
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AndroidPackageInfoFetcher.java b/packages/StatementService/src/com/android/statementservice/retriever/AndroidPackageInfoFetcher.java
deleted file mode 100644
index 1000c4c6e5b2..000000000000
--- a/packages/StatementService/src/com/android/statementservice/retriever/AndroidPackageInfoFetcher.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice.retriever;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources.NotFoundException;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Class that provides information about an android app from {@link PackageManager}.
- *
- * Visible for testing.
- *
- * @hide
- */
-public class AndroidPackageInfoFetcher {
-
- /**
- * The name of the metadata tag in AndroidManifest.xml that stores the associated asset array
- * ID. The metadata tag should use the android:resource attribute to point to an array resource
- * that contains the associated assets.
- */
- private static final String ASSOCIATED_ASSETS_KEY = "associated_assets";
-
- private Context mContext;
-
- public AndroidPackageInfoFetcher(Context context) {
- mContext = context;
- }
-
- /**
- * Returns the Sha-256 fingerprints of all certificates from the specified package as a list of
- * upper case HEX Strings with bytes separated by colons. Given an app {@link
- * android.content.pm.Signature}, the fingerprint can be computed as {@link
- * Utils#computeNormalizedSha256Fingerprint} {@code(signature.toByteArray())}.
- *
- * <p>Given a signed APK, Java 7's commandline keytool can compute the fingerprint using: {@code
- * keytool -list -printcert -jarfile signed_app.apk}
- *
- * <p>Example: "10:39:38:EE:45:37:E5:9E:8E:E7:92:F6:54:50:4F:B8:34:6F:C6:B3:46:D0:BB:C4:41:5F:C3:39:FC:FC:8E:C1"
- *
- * @throws NameNotFoundException if an app with packageName is not installed on the device.
- */
- public List<String> getCertFingerprints(String packageName) throws NameNotFoundException {
- return Utils.getCertFingerprintsFromPackageManager(packageName, mContext);
- }
-
- /**
- * Returns all statements that the specified package makes in its AndroidManifest.xml.
- *
- * @throws NameNotFoundException if the app is not installed on the device.
- */
- public List<String> getStatements(String packageName) throws NameNotFoundException {
- PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(
- packageName, PackageManager.GET_META_DATA);
- ApplicationInfo appInfo = packageInfo.applicationInfo;
- if (appInfo.metaData == null) {
- return Collections.<String>emptyList();
- }
- int tokenResourceId = appInfo.metaData.getInt(ASSOCIATED_ASSETS_KEY);
- if (tokenResourceId == 0) {
- return Collections.<String>emptyList();
- }
- try {
- return Arrays.asList(
- mContext.getPackageManager().getResourcesForApplication(packageName)
- .getStringArray(tokenResourceId));
- } catch (NotFoundException e) {
- return Collections.<String>emptyList();
- }
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AssetFactory.java b/packages/StatementService/src/com/android/statementservice/retriever/AssetFactory.java
index 519d73a22ca6..ac0bfabfbd44 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AssetFactory.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AssetFactory.java
@@ -16,12 +16,14 @@
package com.android.statementservice.retriever;
+import com.android.statementservice.utils.StatementUtils;
+
import org.json.JSONObject;
/**
* Factory to create asset from JSON string.
*/
-/* package private */ final class AssetFactory {
+public final class AssetFactory {
private static final String FIELD_NOT_STRING_FORMAT_STRING = "Expected %s to be string.";
@@ -34,15 +36,15 @@ import org.json.JSONObject;
*/
public static AbstractAsset create(JSONObject asset)
throws AssociationServiceException {
- String namespace = asset.optString(Utils.NAMESPACE_FIELD, null);
+ String namespace = asset.optString(StatementUtils.NAMESPACE_FIELD, null);
if (namespace == null) {
throw new AssociationServiceException(String.format(
- FIELD_NOT_STRING_FORMAT_STRING, Utils.NAMESPACE_FIELD));
+ FIELD_NOT_STRING_FORMAT_STRING, StatementUtils.NAMESPACE_FIELD));
}
- if (namespace.equals(Utils.NAMESPACE_WEB)) {
+ if (namespace.equals(StatementUtils.NAMESPACE_WEB)) {
return WebAsset.create(asset);
- } else if (namespace.equals(Utils.NAMESPACE_ANDROID_APP)) {
+ } else if (namespace.equals(StatementUtils.NAMESPACE_ANDROID_APP)) {
return AndroidAppAsset.create(asset);
} else {
throw new AssociationServiceException("Namespace " + namespace + " is not supported.");
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AssetMatcherFactory.java b/packages/StatementService/src/com/android/statementservice/retriever/AssetMatcherFactory.java
index 1a50757d932f..7773668551a5 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AssetMatcherFactory.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AssetMatcherFactory.java
@@ -16,6 +16,8 @@
package com.android.statementservice.retriever;
+import com.android.statementservice.utils.StatementUtils;
+
import org.json.JSONException;
import org.json.JSONObject;
@@ -31,15 +33,15 @@ import org.json.JSONObject;
JSONException {
JSONObject queryObject = new JSONObject(query);
- String namespace = queryObject.optString(Utils.NAMESPACE_FIELD, null);
+ String namespace = queryObject.optString(StatementUtils.NAMESPACE_FIELD, null);
if (namespace == null) {
throw new AssociationServiceException(String.format(
- FIELD_NOT_STRING_FORMAT_STRING, Utils.NAMESPACE_FIELD));
+ FIELD_NOT_STRING_FORMAT_STRING, StatementUtils.NAMESPACE_FIELD));
}
- if (namespace.equals(Utils.NAMESPACE_WEB)) {
+ if (namespace.equals(StatementUtils.NAMESPACE_WEB)) {
return new WebAssetMatcher(WebAsset.create(queryObject));
- } else if (namespace.equals(Utils.NAMESPACE_ANDROID_APP)) {
+ } else if (namespace.equals(StatementUtils.NAMESPACE_ANDROID_APP)) {
return new AndroidAppAssetMatcher(AndroidAppAsset.create(queryObject));
} else {
throw new AssociationServiceException(
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
deleted file mode 100644
index 9839329bf34c..000000000000
--- a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice.retriever;
-
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.util.Log;
-
-import org.json.JSONException;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * An implementation of {@link AbstractStatementRetriever} that directly retrieves statements from
- * the asset.
- */
-/* package private */ final class DirectStatementRetriever extends AbstractStatementRetriever {
-
- private static final long DO_NOT_CACHE_RESULT = 0L;
- private static final int HTTP_CONNECTION_TIMEOUT_MILLIS = 5000;
- private static final int HTTP_CONNECTION_BACKOFF_MILLIS = 3000;
- private static final int HTTP_CONNECTION_RETRY = 3;
- private static final long HTTP_CONTENT_SIZE_LIMIT_IN_BYTES = 1024 * 1024;
- private static final int MAX_INCLUDE_LEVEL = 1;
- private static final String WELL_KNOWN_STATEMENT_PATH = "/.well-known/assetlinks.json";
-
- private final URLFetcher mUrlFetcher;
- private final AndroidPackageInfoFetcher mAndroidFetcher;
-
- /**
- * An immutable value type representing the retrieved statements and the expiration date.
- */
- public static class Result implements AbstractStatementRetriever.Result {
-
- private final List<Statement> mStatements;
- private final Long mExpireMillis;
-
- @Override
- public List<Statement> getStatements() {
- return mStatements;
- }
-
- @Override
- public long getExpireMillis() {
- return mExpireMillis;
- }
-
- private Result(List<Statement> statements, Long expireMillis) {
- mStatements = statements;
- mExpireMillis = expireMillis;
- }
-
- public static Result create(List<Statement> statements, Long expireMillis) {
- return new Result(statements, expireMillis);
- }
-
- @Override
- public String toString() {
- StringBuilder result = new StringBuilder();
- result.append("Result: ");
- result.append(mStatements.toString());
- result.append(", mExpireMillis=");
- result.append(mExpireMillis);
- return result.toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- Result result = (Result) o;
-
- if (!mExpireMillis.equals(result.mExpireMillis)) {
- return false;
- }
- if (!mStatements.equals(result.mStatements)) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = mStatements.hashCode();
- result = 31 * result + mExpireMillis.hashCode();
- return result;
- }
- }
-
- public DirectStatementRetriever(URLFetcher urlFetcher,
- AndroidPackageInfoFetcher androidFetcher) {
- this.mUrlFetcher = urlFetcher;
- this.mAndroidFetcher = androidFetcher;
- }
-
- @Override
- public Result retrieveStatements(AbstractAsset source) throws AssociationServiceException {
- if (source instanceof AndroidAppAsset) {
- return retrieveFromAndroid((AndroidAppAsset) source);
- } else if (source instanceof WebAsset) {
- return retrieveFromWeb((WebAsset) source);
- } else {
- throw new AssociationServiceException("Namespace is not supported.");
- }
- }
-
- private String computeAssociationJsonUrl(WebAsset asset) {
- try {
- return new URL(asset.getScheme(), asset.getDomain(), asset.getPort(),
- WELL_KNOWN_STATEMENT_PATH)
- .toExternalForm();
- } catch (MalformedURLException e) {
- throw new AssertionError("Invalid domain name in database.");
- }
- }
-
- private Result retrieveStatementFromUrl(String urlString, int maxIncludeLevel,
- AbstractAsset source)
- throws AssociationServiceException {
- List<Statement> statements = new ArrayList<Statement>();
- if (maxIncludeLevel < 0) {
- return Result.create(statements, DO_NOT_CACHE_RESULT);
- }
-
- WebContent webContent;
- try {
- URL url = new URL(urlString);
- if (!source.followInsecureInclude()
- && !url.getProtocol().toLowerCase().equals("https")) {
- return Result.create(statements, DO_NOT_CACHE_RESULT);
- }
- webContent = mUrlFetcher.getWebContentFromUrlWithRetry(url,
- HTTP_CONTENT_SIZE_LIMIT_IN_BYTES, HTTP_CONNECTION_TIMEOUT_MILLIS,
- HTTP_CONNECTION_BACKOFF_MILLIS, HTTP_CONNECTION_RETRY);
- } catch (IOException | InterruptedException e) {
- return Result.create(statements, DO_NOT_CACHE_RESULT);
- }
-
- try {
- ParsedStatement result = StatementParser
- .parseStatementList(webContent.getContent(), source);
- statements.addAll(result.getStatements());
- for (String delegate : result.getDelegates()) {
- statements.addAll(
- retrieveStatementFromUrl(delegate, maxIncludeLevel - 1, source)
- .getStatements());
- }
- return Result.create(statements, webContent.getExpireTimeMillis());
- } catch (JSONException | IOException e) {
- return Result.create(statements, DO_NOT_CACHE_RESULT);
- }
- }
-
- private Result retrieveFromWeb(WebAsset asset)
- throws AssociationServiceException {
- return retrieveStatementFromUrl(computeAssociationJsonUrl(asset), MAX_INCLUDE_LEVEL, asset);
- }
-
- private Result retrieveFromAndroid(AndroidAppAsset asset) throws AssociationServiceException {
- try {
- List<String> delegates = new ArrayList<String>();
- List<Statement> statements = new ArrayList<Statement>();
-
- List<String> certFps = mAndroidFetcher.getCertFingerprints(asset.getPackageName());
- if (!Utils.hasCommonString(certFps, asset.getCertFingerprints())) {
- throw new AssociationServiceException(
- "Specified certs don't match the installed app.");
- }
-
- AndroidAppAsset actualSource = AndroidAppAsset.create(asset.getPackageName(), certFps);
- for (String statementJson : mAndroidFetcher.getStatements(asset.getPackageName())) {
- ParsedStatement result =
- StatementParser.parseStatement(statementJson, actualSource);
- statements.addAll(result.getStatements());
- delegates.addAll(result.getDelegates());
- }
-
- for (String delegate : delegates) {
- statements.addAll(retrieveStatementFromUrl(delegate, MAX_INCLUDE_LEVEL,
- actualSource).getStatements());
- }
-
- return Result.create(statements, DO_NOT_CACHE_RESULT);
- } catch (JSONException | IOException | NameNotFoundException e) {
- Log.w(DirectStatementRetriever.class.getSimpleName(), e);
- return Result.create(Collections.<Statement>emptyList(), DO_NOT_CACHE_RESULT);
- }
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/ParsedStatement.java b/packages/StatementService/src/com/android/statementservice/retriever/ParsedStatement.java
deleted file mode 100644
index 9446e660978a..000000000000
--- a/packages/StatementService/src/com/android/statementservice/retriever/ParsedStatement.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice.retriever;
-
-import java.util.List;
-
-/**
- * A class that stores a list of statement and/or a list of delegate url.
- */
-/* package private */ final class ParsedStatement {
-
- private final List<Statement> mStatements;
- private final List<String> mDelegates;
-
- public ParsedStatement(List<Statement> statements, List<String> delegates) {
- this.mStatements = statements;
- this.mDelegates = delegates;
- }
-
- public List<Statement> getStatements() {
- return mStatements;
- }
-
- public List<String> getDelegates() {
- return mDelegates;
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Statement.java b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
index 0f40a6221017..f8bab3ef170f 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
@@ -17,6 +17,11 @@
package com.android.statementservice.retriever;
import android.annotation.NonNull;
+import android.net.Network;
+
+import com.android.statementservice.network.retriever.StatementRetriever;
+
+import kotlin.coroutines.Continuation;
/**
* An immutable value type representing a statement, consisting of a source, target, and relation.
@@ -31,9 +36,9 @@ import android.annotation.NonNull;
* }
* </pre>
*
- * Then invoking {@link AbstractStatementRetriever#retrieveStatements(AbstractAsset)} will return a
- * {@link Statement} with {@link #getSource} equal to the input parameter, {@link #getRelation}
- * equal to
+ * Then invoking {@link StatementRetriever#retrieve(AbstractAsset, Network, Continuation)} will
+ * return a {@link Statement} with {@link #getSource} equal to the input parameter,
+ * {@link #getRelation} equal to
*
* <pre>Relation.create("delegate_permission", "common.get_login_creds");</pre>
*
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/StatementParser.java b/packages/StatementService/src/com/android/statementservice/retriever/StatementParser.java
deleted file mode 100644
index 0369718ee507..000000000000
--- a/packages/StatementService/src/com/android/statementservice/retriever/StatementParser.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice.retriever;
-
-import android.util.JsonReader;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Utility class that parses JSON-formatted statements.
- */
-/* package private */ final class StatementParser {
-
- private static final String FIELD_NOT_STRING_FORMAT_STRING = "Expected %s to be string.";
- private static final String FIELD_NOT_ARRAY_FORMAT_STRING = "Expected %s to be array.";
-
- /**
- * Parses a JSON array of statements.
- */
- static ParsedStatement parseStatementList(String statementList, AbstractAsset source)
- throws JSONException, IOException {
- List<Statement> statements = new ArrayList<Statement>();
- List<String> delegates = new ArrayList<String>();
-
- JsonReader reader = new JsonReader(new StringReader(statementList));
- reader.setLenient(false);
-
- reader.beginArray();
- while (reader.hasNext()) {
- ParsedStatement result;
- try {
- result = parseStatement(reader, source);
- } catch (AssociationServiceException e) {
- // The element in the array is well formatted Json but not a well-formed Statement.
- continue;
- }
- statements.addAll(result.getStatements());
- delegates.addAll(result.getDelegates());
- }
- reader.endArray();
-
- return new ParsedStatement(statements, delegates);
- }
-
- /**
- * Parses a single JSON statement.
- */
- static ParsedStatement parseStatement(String statementString, AbstractAsset source)
- throws AssociationServiceException, IOException, JSONException {
- JsonReader reader = new JsonReader(new StringReader(statementString));
- reader.setLenient(false);
- return parseStatement(reader, source);
- }
-
- /**
- * Parses a single JSON statement. This method guarantees that exactly one JSON object
- * will be consumed.
- */
- static ParsedStatement parseStatement(JsonReader reader, AbstractAsset source)
- throws JSONException, AssociationServiceException, IOException {
- List<Statement> statements = new ArrayList<Statement>();
- List<String> delegates = new ArrayList<String>();
-
- JSONObject statement = JsonParser.parse(reader);
-
- if (statement.optString(Utils.DELEGATE_FIELD_DELEGATE, null) != null) {
- delegates.add(statement.optString(Utils.DELEGATE_FIELD_DELEGATE));
- } else {
- JSONObject targetObject = statement.optJSONObject(Utils.ASSET_DESCRIPTOR_FIELD_TARGET);
- if (targetObject == null) {
- throw new AssociationServiceException(String.format(
- FIELD_NOT_STRING_FORMAT_STRING, Utils.ASSET_DESCRIPTOR_FIELD_TARGET));
- }
-
- JSONArray relations = statement.optJSONArray(Utils.ASSET_DESCRIPTOR_FIELD_RELATION);
- if (relations == null) {
- throw new AssociationServiceException(String.format(
- FIELD_NOT_ARRAY_FORMAT_STRING, Utils.ASSET_DESCRIPTOR_FIELD_RELATION));
- }
-
- AbstractAsset target = AssetFactory.create(targetObject);
- for (int i = 0; i < relations.length(); i++) {
- statements.add(Statement
- .create(source, target, Relation.create(relations.getString(i))));
- }
- }
-
- return new ParsedStatement(statements, delegates);
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
deleted file mode 100644
index 23cd83221fdc..000000000000
--- a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice.retriever;
-
-import android.util.Log;
-
-import com.android.volley.Cache;
-import com.android.volley.NetworkResponse;
-import com.android.volley.toolbox.HttpHeaderParser;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Helper class for fetching HTTP or HTTPS URL.
- *
- * Visible for testing.
- *
- * @hide
- */
-public class URLFetcher {
- private static final String TAG = URLFetcher.class.getSimpleName();
-
- private static final long DO_NOT_CACHE_RESULT = 0L;
- private static final int INPUT_BUFFER_SIZE_IN_BYTES = 1024;
-
- /**
- * Fetches the specified url and returns the content and ttl.
- *
- * <p>
- * Retry {@code retry} times if the connection failed or timed out for any reason.
- * HTTP error code (e.g. 404/500) won't be retried.
- *
- * @throws IOException if it can't retrieve the content due to a network problem.
- * @throws AssociationServiceException if the URL scheme is not http or https or the content
- * length exceeds {code fileSizeLimit}.
- */
- public WebContent getWebContentFromUrlWithRetry(URL url, long fileSizeLimit,
- int connectionTimeoutMillis, int backoffMillis, int retry)
- throws AssociationServiceException, IOException, InterruptedException {
- if (retry <= 0) {
- throw new IllegalArgumentException("retry should be a postive inetger.");
- }
- while (retry > 0) {
- try {
- return getWebContentFromUrl(url, fileSizeLimit, connectionTimeoutMillis);
- } catch (IOException e) {
- retry--;
- if (retry == 0) {
- throw e;
- }
- }
-
- Thread.sleep(backoffMillis);
- }
-
- // Should never reach here.
- return null;
- }
-
- /**
- * Fetches the specified url and returns the content and ttl.
- *
- * @throws IOException if it can't retrieve the content due to a network problem.
- * @throws AssociationServiceException if the URL scheme is not http or https or the content
- * length exceeds {code fileSizeLimit}.
- */
- public WebContent getWebContentFromUrl(URL url, long fileSizeLimit, int connectionTimeoutMillis)
- throws AssociationServiceException, IOException {
- final String scheme = url.getProtocol().toLowerCase(Locale.US);
- if (!scheme.equals("http") && !scheme.equals("https")) {
- throw new IllegalArgumentException("The url protocol should be on http or https.");
- }
-
- HttpURLConnection connection = null;
- try {
- connection = (HttpURLConnection) url.openConnection();
- connection.setInstanceFollowRedirects(true);
- connection.setConnectTimeout(connectionTimeoutMillis);
- connection.setReadTimeout(connectionTimeoutMillis);
- connection.setUseCaches(true);
- connection.setInstanceFollowRedirects(false);
- connection.addRequestProperty("Cache-Control", "max-stale=60");
-
- if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
- Log.e(TAG, "The responses code is not 200 but " + connection.getResponseCode());
- return new WebContent("", DO_NOT_CACHE_RESULT);
- }
-
- if (connection.getContentLength() > fileSizeLimit) {
- Log.e(TAG, "The content size of the url is larger than " + fileSizeLimit);
- return new WebContent("", DO_NOT_CACHE_RESULT);
- }
-
- Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(
- connection.getHeaderFields());
-
- return new WebContent(inputStreamToString(
- connection.getInputStream(), connection.getContentLength(), fileSizeLimit),
- expireTimeMillis);
- } finally {
- if (connection != null) {
- connection.disconnect();
- }
- }
- }
-
- /**
- * Visible for testing.
- * @hide
- */
- public static String inputStreamToString(InputStream inputStream, int length, long sizeLimit)
- throws IOException, AssociationServiceException {
- if (length < 0) {
- length = 0;
- }
- ByteArrayOutputStream baos = new ByteArrayOutputStream(length);
- BufferedInputStream bis = new BufferedInputStream(inputStream);
- byte[] buffer = new byte[INPUT_BUFFER_SIZE_IN_BYTES];
- int len = 0;
- while ((len = bis.read(buffer)) != -1) {
- baos.write(buffer, 0, len);
- if (baos.size() > sizeLimit) {
- throw new AssociationServiceException("The content size of the url is larger than "
- + sizeLimit);
- }
- }
- return baos.toString("UTF-8");
- }
-
- /**
- * Parses the HTTP headers to compute the ttl.
- *
- * @param headers a map that map the header key to the header values. Can be null.
- * @return the ttl in millisecond or null if the ttl is not specified in the header.
- */
- private Long getExpirationTimeMillisFromHTTPHeader(Map<String, List<String>> headers) {
- if (headers == null) {
- return null;
- }
- Map<String, String> joinedHeaders = joinHttpHeaders(headers);
-
- NetworkResponse response = new NetworkResponse(null, joinedHeaders);
- Cache.Entry cachePolicy = HttpHeaderParser.parseCacheHeaders(response);
-
- if (cachePolicy == null) {
- // Cache is disabled, set the expire time to 0.
- return DO_NOT_CACHE_RESULT;
- } else if (cachePolicy.ttl == 0) {
- // Cache policy is not specified, set the expire time to 0.
- return DO_NOT_CACHE_RESULT;
- } else {
- // cachePolicy.ttl is actually the expire timestamp in millisecond.
- return cachePolicy.ttl;
- }
- }
-
- /**
- * Converts an HTTP header map of the format provided by {@linkHttpUrlConnection} to a map of
- * the format accepted by {@link HttpHeaderParser}. It does this by joining all the entries for
- * a given header key with ", ".
- */
- private Map<String, String> joinHttpHeaders(Map<String, List<String>> headers) {
- Map<String, String> joinedHeaders = new HashMap<String, String>();
- for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
- List<String> values = entry.getValue();
- if (values.size() == 1) {
- joinedHeaders.put(entry.getKey(), values.get(0));
- } else {
- joinedHeaders.put(entry.getKey(), Utils.joinStrings(", ", values));
- }
- }
- return joinedHeaders;
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Utils.java b/packages/StatementService/src/com/android/statementservice/retriever/Utils.java
deleted file mode 100644
index afb4c7507401..000000000000
--- a/packages/StatementService/src/com/android/statementservice/retriever/Utils.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2015 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.statementservice.retriever;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.Signature;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-
-/**
- * Utility library for computing certificate fingerprints. Also includes fields name used by
- * Statement JSON string.
- */
-public final class Utils {
-
- private Utils() {}
-
- /**
- * Field name for namespace.
- */
- public static final String NAMESPACE_FIELD = "namespace";
-
- /**
- * Supported asset namespaces.
- */
- public static final String NAMESPACE_WEB = "web";
- public static final String NAMESPACE_ANDROID_APP = "android_app";
-
- /**
- * Field names in a web asset descriptor.
- */
- public static final String WEB_ASSET_FIELD_SITE = "site";
-
- /**
- * Field names in a Android app asset descriptor.
- */
- public static final String ANDROID_APP_ASSET_FIELD_PACKAGE_NAME = "package_name";
- public static final String ANDROID_APP_ASSET_FIELD_CERT_FPS = "sha256_cert_fingerprints";
-
- /**
- * Field names in a statement.
- */
- public static final String ASSET_DESCRIPTOR_FIELD_RELATION = "relation";
- public static final String ASSET_DESCRIPTOR_FIELD_TARGET = "target";
- public static final String DELEGATE_FIELD_DELEGATE = "include";
-
- private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F' };
-
- /**
- * Joins a list of strings, by placing separator between each string. For example,
- * {@code joinStrings("; ", Arrays.asList(new String[]{"a", "b", "c"}))} returns
- * "{@code a; b; c}".
- */
- public static String joinStrings(String separator, List<String> strings) {
- switch(strings.size()) {
- case 0:
- return "";
- case 1:
- return strings.get(0);
- default:
- StringBuilder joiner = new StringBuilder();
- boolean first = true;
- for (String field : strings) {
- if (first) {
- first = false;
- } else {
- joiner.append(separator);
- }
- joiner.append(field);
- }
- return joiner.toString();
- }
- }
-
- /**
- * Returns the normalized sha-256 fingerprints of a given package according to the Android
- * package manager.
- */
- public static List<String> getCertFingerprintsFromPackageManager(String packageName,
- Context context) throws NameNotFoundException {
- Signature[] signatures = context.getPackageManager().getPackageInfo(packageName,
- PackageManager.GET_SIGNATURES).signatures;
- ArrayList<String> result = new ArrayList<String>(signatures.length);
- for (Signature sig : signatures) {
- result.add(computeNormalizedSha256Fingerprint(sig.toByteArray()));
- }
- return result;
- }
-
- /**
- * Computes the hash of the byte array using the specified algorithm, returning a hex string
- * with a colon between each byte.
- */
- public static String computeNormalizedSha256Fingerprint(byte[] signature) {
- MessageDigest digester;
- try {
- digester = MessageDigest.getInstance("SHA-256");
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError("No SHA-256 implementation found.");
- }
- digester.update(signature);
- return byteArrayToHexString(digester.digest());
- }
-
- /**
- * Returns true if there is at least one common string between the two lists of string.
- */
- public static boolean hasCommonString(List<String> list1, List<String> list2) {
- HashSet<String> set2 = new HashSet<>(list2);
- for (String string : list1) {
- if (set2.contains(string)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Converts the byte array to an lowercase hexadecimal digits String with a colon character (:)
- * between each byte.
- */
- private static String byteArrayToHexString(byte[] array) {
- if (array.length == 0) {
- return "";
- }
- char[] buf = new char[array.length * 3 - 1];
-
- int bufIndex = 0;
- for (int i = 0; i < array.length; i++) {
- byte b = array[i];
- if (i > 0) {
- buf[bufIndex++] = ':';
- }
- buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
- buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
- }
- return new String(buf);
- }
-}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java
index 947087a553f5..608ce6926efa 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java
@@ -16,6 +16,8 @@
package com.android.statementservice.retriever;
+import com.android.statementservice.utils.StatementUtils;
+
import org.json.JSONObject;
import java.net.MalformedURLException;
@@ -36,7 +38,7 @@ import java.util.Locale;
* <p>The only protocol supported now are https and http. If the optional port is not specified,
* the default for each protocol will be used (i.e. 80 for http and 443 for https).
*/
-/* package private */ final class WebAsset extends AbstractAsset {
+public final class WebAsset extends AbstractAsset {
private static final String MISSING_FIELD_FORMAT_STRING = "Expected %s to be set.";
private static final String SCHEME_HTTP = "http";
@@ -73,8 +75,8 @@ import java.util.Locale;
public String toJson() {
AssetJsonWriter writer = new AssetJsonWriter();
- writer.writeFieldLower(Utils.NAMESPACE_FIELD, Utils.NAMESPACE_WEB);
- writer.writeFieldLower(Utils.WEB_ASSET_FIELD_SITE, mUrl.toExternalForm());
+ writer.writeFieldLower(StatementUtils.NAMESPACE_FIELD, StatementUtils.NAMESPACE_WEB);
+ writer.writeFieldLower(StatementUtils.WEB_ASSET_FIELD_SITE, mUrl.toExternalForm());
return writer.closeAndGetString();
}
@@ -119,14 +121,14 @@ import java.util.Locale;
*/
protected static WebAsset create(JSONObject asset)
throws AssociationServiceException {
- if (asset.optString(Utils.WEB_ASSET_FIELD_SITE).equals("")) {
+ if (asset.optString(StatementUtils.WEB_ASSET_FIELD_SITE).equals("")) {
throw new AssociationServiceException(String.format(MISSING_FIELD_FORMAT_STRING,
- Utils.WEB_ASSET_FIELD_SITE));
+ StatementUtils.WEB_ASSET_FIELD_SITE));
}
URL url;
try {
- url = new URL(asset.optString(Utils.WEB_ASSET_FIELD_SITE));
+ url = new URL(asset.optString(StatementUtils.WEB_ASSET_FIELD_SITE));
} catch (MalformedURLException e) {
throw new AssociationServiceException("Url is not well formatted.", e);
}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/WebContent.java b/packages/StatementService/src/com/android/statementservice/retriever/WebContent.java
index 86a635c16436..23b1f9b894f4 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/WebContent.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/WebContent.java
@@ -27,10 +27,12 @@ public final class WebContent {
private final String mContent;
private final Long mExpireTimeMillis;
+ private final int mResponseCode;
- public WebContent(String content, Long expireTimeMillis) {
+ public WebContent(String content, Long expireTimeMillis, int responseCode) {
mContent = content;
mExpireTimeMillis = expireTimeMillis;
+ mResponseCode = responseCode;
}
/**
@@ -46,4 +48,8 @@ public final class WebContent {
public String getContent() {
return mContent;
}
+
+ public int getResponseCode() {
+ return mResponseCode;
+ }
}
diff --git a/packages/StatementService/src/com/android/statementservice/utils/AndroidUtils.kt b/packages/StatementService/src/com/android/statementservice/utils/AndroidUtils.kt
new file mode 100644
index 000000000000..7fe0a029088b
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/utils/AndroidUtils.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 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.statementservice.utils
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.pm.verify.domain.DomainVerificationInfo
+import android.content.pm.verify.domain.DomainVerificationRequest
+import android.content.pm.verify.domain.DomainVerificationUserState
+import com.android.statementservice.domain.DomainVerificationReceiverV1
+import com.android.statementservice.domain.DomainVerificationReceiverV2
+
+// Top level extensions for models to allow Kotlin deconstructing declarations
+
+operator fun DomainVerificationRequest.component1() = packageNames
+
+operator fun DomainVerificationInfo.component1() = identifier
+operator fun DomainVerificationInfo.component2() = packageName
+operator fun DomainVerificationInfo.component3() = hostToStateMap
+
+operator fun DomainVerificationUserState.component1() = identifier
+operator fun DomainVerificationUserState.component2() = packageName
+operator fun DomainVerificationUserState.component3() = user
+operator fun DomainVerificationUserState.component4() = isLinkHandlingAllowed
+operator fun DomainVerificationUserState.component5() = hostToStateMap
+
+object AndroidUtils {
+
+ fun isReceiverV1Enabled(context: Context): Boolean {
+ val receiver = ComponentName(context, DomainVerificationReceiverV1::class.java)
+ return when (context.packageManager.getComponentEnabledSetting(receiver)) {
+ // Must change this if the manifest ever changes
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT -> true
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> true
+ else -> false
+ }
+ }
+
+ fun isReceiverV2Enabled(context: Context): Boolean {
+ val receiver = ComponentName(context, DomainVerificationReceiverV2::class.java)
+ return when (context.packageManager.getComponentEnabledSetting(receiver)) {
+ // Must change this if the manifest ever changes
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT -> false
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> true
+ else -> false
+ }
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/utils/Result.kt b/packages/StatementService/src/com/android/statementservice/utils/Result.kt
new file mode 100644
index 000000000000..f23a010744e9
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/utils/Result.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 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.statementservice.utils
+
+sealed class Result<T> {
+
+ fun successValueOrNull() = (this as? Success<T>)?.value
+
+ data class Success<T>(val value: T) : Result<T>()
+ data class Failure<T>(val message: String? = null, val throwable: Throwable? = null) :
+ Result<T>() {
+
+ constructor(message: String) : this(message = message, throwable = null)
+ constructor(throwable: Throwable) : this(message = null, throwable = throwable)
+
+ @Suppress("UNCHECKED_CAST")
+ fun <T> asType() = this as Result<T>
+ }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/utils/StatementUtils.kt b/packages/StatementService/src/com/android/statementservice/utils/StatementUtils.kt
new file mode 100644
index 000000000000..92d752c83a9f
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/utils/StatementUtils.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2021 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.statementservice.utils
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.util.Patterns
+import com.android.statementservice.retriever.Relation
+import java.net.URL
+import java.security.MessageDigest
+
+internal object StatementUtils {
+
+ /**
+ * Field name for namespace.
+ */
+ const val NAMESPACE_FIELD = "namespace"
+
+ /**
+ * Supported asset namespaces.
+ */
+ const val NAMESPACE_WEB = "web"
+ const val NAMESPACE_ANDROID_APP = "android_app"
+
+ /**
+ * Field names in a web asset descriptor.
+ */
+ const val WEB_ASSET_FIELD_SITE = "site"
+
+ /**
+ * Field names in a Android app asset descriptor.
+ */
+ const val ANDROID_APP_ASSET_FIELD_PACKAGE_NAME = "package_name"
+ const val ANDROID_APP_ASSET_FIELD_CERT_FPS = "sha256_cert_fingerprints"
+
+ /**
+ * Field names in a statement.
+ */
+ const val ASSET_DESCRIPTOR_FIELD_RELATION = "relation"
+ const val ASSET_DESCRIPTOR_FIELD_TARGET = "target"
+ const val DELEGATE_FIELD_DELEGATE = "include"
+
+ val HEX_DIGITS =
+ charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
+
+ val RELATION by lazy { Relation.create("delegate_permission/common.handle_all_urls") }
+ private const val ANDROID_ASSET_FORMAT =
+ """{"namespace": "android_app", "package_name": "%s", "sha256_cert_fingerprints": [%s]}"""
+ private const val WEB_ASSET_FORMAT = """{"namespace": "web", "site": "%s"}"""
+
+ private val digesterSha256 by lazy { tryOrNull { MessageDigest.getInstance("SHA-256") } }
+
+ internal inline fun <T> tryOrNull(block: () -> T) =
+ try {
+ block()
+ } catch (ignored: Exception) {
+ null
+ }
+
+ /**
+ * Returns the normalized sha-256 fingerprints of a given package according to the Android
+ * package manager.
+ */
+ fun getCertFingerprintsFromPackageManager(
+ context: Context,
+ packageName: String
+ ): Result<List<String>> {
+ val signingInfo = try {
+ context.packageManager.getPackageInfo(
+ packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES or PackageManager.MATCH_ANY_USER
+ )
+ .signingInfo
+ } catch (e: Exception) {
+ return Result.Failure(e)
+ }
+ return if (signingInfo.hasMultipleSigners()) {
+ signingInfo.apkContentsSigners
+ } else {
+ signingInfo.signingCertificateHistory
+ }.map {
+ val result = computeNormalizedSha256Fingerprint(it.toByteArray())
+ if (result is Result.Failure) {
+ return result.asType()
+ } else {
+ (result as Result.Success).value
+ }
+ }.let { Result.Success(it) }
+ }
+
+ /**
+ * Computes the hash of the byte array using the specified algorithm, returning a hex string
+ * with a colon between each byte.
+ */
+ fun computeNormalizedSha256Fingerprint(signature: ByteArray) =
+ digesterSha256?.digest(signature)
+ ?.let(StatementUtils::bytesToHexString)
+ ?.let { Result.Success(it) }
+ ?: Result.Failure()
+
+ private fun bytesToHexString(bytes: ByteArray): String {
+ val hexChars = CharArray(bytes.size * 3 - 1)
+ var bufIndex = 0
+ for (index in bytes.indices) {
+ val byte = bytes[index].toInt() and 0xFF
+ if (index > 0) {
+ hexChars[bufIndex++] = ':'
+ }
+
+ hexChars[bufIndex++] = HEX_DIGITS[byte ushr 4]
+ hexChars[bufIndex++] = HEX_DIGITS[byte and 0x0F]
+ }
+ return String(hexChars)
+ }
+
+ fun createAndroidAssetString(context: Context, packageName: String): Result<String> {
+ val result = getCertFingerprintsFromPackageManager(context, packageName)
+ if (result is Result.Failure) {
+ return result.asType()
+ }
+ return Result.Success(
+ ANDROID_ASSET_FORMAT.format(
+ packageName,
+ (result as Result.Success).value.joinToString(separator = "\", \"")
+ )
+ )
+ }
+
+ fun createAndroidAsset(packageName: String, certFingerprints: List<String>) =
+ String.format(
+ ANDROID_ASSET_FORMAT,
+ packageName,
+ certFingerprints.joinToString(separator = ", ") { "\"$it\"" })
+
+ fun createWebAssetString(scheme: String, host: String): Result<String> {
+ if (!Patterns.DOMAIN_NAME.matcher(host).matches()) {
+ return Result.Failure("Input host is not valid.")
+ }
+ if (scheme != "http" && scheme != "https") {
+ return Result.Failure("Input scheme is not valid.")
+ }
+ return Result.Success(WEB_ASSET_FORMAT.format(URL(scheme, host, "").toString()))
+ }
+
+ // Hosts with *. for wildcard subdomain support are verified against their root domain
+ fun createWebAssetString(host: String) =
+ WEB_ASSET_FORMAT.format(URL("https", host.removePrefix("*."), "").toString())
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
index 457e8e6e9a5f..659b9fee8656 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -94,6 +94,16 @@ public class Interpolators {
}
/**
+ * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
+ * starts immediately here, instead of first having a section of non-overshooting
+ *
+ * @param progress a progress value going from 0 to 1
+ */
+ public static float getOvershootInterpolation(float progress) {
+ return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
+ }
+
+ /**
* Interpolate alpha for notifications background scrim during shade expansion.
* @param fraction Shade expansion fraction
* @param forNotification If we want the alpha of the notification shade or the scrim.
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 4ca4c1b7ece3..b307544f5e3c 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -89,7 +89,7 @@
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM को PIN कोड गलत छ। तपाईंले अब आफ्नो यन्त्र खोल्न आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नै पर्ने हुन्छ।"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
<item quantity="other">SIM को PIN कोड गलत छ, तपाईं अझै <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास गर्न सक्नुहुन्छ।</item>
- <item quantity="one">SIM को PIN कोड गलत छ,तपाईंले आफ्नो यन्त्र अनलक गर्न आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नैपर्ने अवस्था आउनु अघि तपाईं अझै <xliff:g id="NUMBER_0">%d</xliff:g> पटक प्रयास गर्न सक्नुहुन्छ।</item>
+ <item quantity="one">SIM को PIN कोड गलत छ,तपाईंले आफ्नो डिभाइस अनलक गर्न आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नैपर्ने अवस्था आउनु अघि तपाईं अझै <xliff:g id="NUMBER_0">%d</xliff:g> पटक प्रयास गर्न सक्नुहुन्छ।</item>
</plurals>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"SIM काम नलाग्ने भएको छ। आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।"</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="3937306685604862886">
@@ -129,7 +129,7 @@
<string name="kg_face_not_recognized" msgid="7903950626744419160">"पहिचान भएन"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
<item quantity="other">SIM को PIN प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="NUMBER_1">%d</xliff:g>  प्रयासहरू बाँकी छन्।</item>
- <item quantity="one">SIM को PIN प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="NUMBER_0">%d</xliff:g> प्रयास बाँकी छ, त्यसपछि भने आफ्नो यन्त्र अनलक गर्नका लागि तपाईंले अनिवार्य रूपमा आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नु पर्ने हुन्छ।</item>
+ <item quantity="one">SIM को PIN प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="NUMBER_0">%d</xliff:g> प्रयास बाँकी छ, त्यसपछि भने आफ्नो डिभाइस अनलक गर्नका लागि तपाईंले अनिवार्य रूपमा आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नु पर्ने हुन्छ।</item>
</plurals>
<plurals name="kg_password_default_puk_message" formatted="false" msgid="571308542462946935">
<item quantity="other">SIM लाई असक्षम पारिएको छ। जारी राख्न PUK कोड प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयासहरू बाँकी छन्, त्यसपछि SIM सदाका लागि प्रयोग गर्न नमिल्ने हुन्छ। विवरणहरूका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</item>
diff --git a/packages/SystemUI/res-product/values-ky/strings.xml b/packages/SystemUI/res-product/values-ky/strings.xml
index 4eb90caa4391..00265a187ddf 100644
--- a/packages/SystemUI/res-product/values-ky/strings.xml
+++ b/packages/SystemUI/res-product/values-ky/strings.xml
@@ -26,18 +26,18 @@
<string name="keyguard_missing_sim_message" product="tablet" msgid="5018086454277963787">"Планшетте SIM-карта жок."</string>
<string name="keyguard_missing_sim_message" product="default" msgid="7053347843877341391">"Телефондо SIM-карта жок."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="6278551068943958651">"PIN-коддор дал келген жок"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="302165994845009232">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул планшет баштапкы абалга келтирилип, андагы бардык маалымат өчүрүлөт."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="2594813176164266847">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул телефон баштапкы абалга келтирилип, андагы бардык маалымат өчүрүлөт."</string>
- <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="8710104080409538587">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Бул планшет баштапкы абалга келтирилип, андагы бардык маалымат өчүрүлөт."</string>
- <string name="kg_failed_attempts_now_wiping" product="default" msgid="6381835450014881813">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет жасадыңыз. Бул телефон баштапкы абалга келтирилип, андагы бардык маалымат өчүрүлөт."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="302165994845009232">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул планшет баштапкы абалга келтирилип, андагы бардык нерселер өчүрүлөт."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="2594813176164266847">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул телефон баштапкы абалга келтирилип, андагы бардык нерселер өчүрүлөт."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="8710104080409538587">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Бул планшет баштапкы абалга келтирилип, андагы бардык нерселер өчүрүлөт."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="6381835450014881813">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет жасадыңыз. Бул телефон баштапкы абалга келтирилип, андагы бардык нерселер өчүрүлөт."</string>
<string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="7325071812832605911">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу өчүрүлүп, колдонуучунун бардык маалыматы өчүрүлөт."</string>
<string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="8110939900089863103">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу өчүрүлүп, колдонуучунун бардык маалыматы өчүрүлөт."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="8509811676952707883">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Бул колдонуучу өчүрүлүп, колдонуучунун бардык маалыматы өчүрүлөт."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="3051962486994265014">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Бул колдонуучу өчүрүлүп, колдонуучунун бардык маалыматы өчүрүлөт."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="1049523640263353830">"Планшетиңиздин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, жумуш профилиңиз өчүрүлүп, профилдеги бардык маалымат өчүрүлөт."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, жумуш профилиңиз өчүрүлүп, профилдеги бардык маалымат өчүрүлөт."</string>
- <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили өчүрүлүп, андагы бардык маалымат өчүрүлөт."</string>
- <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили өчүрүлүп, андагы бардык маалымат өчүрүлөт."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="1049523640263353830">"Планшетиңиздин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, жумуш профилиңиз өчүрүлүп, профилдеги бардык нерселер өчүрүлөт."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, жумуш профилиңиз өчүрүлүп, профилдеги бардык нерселер өчүрүлөт."</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили өчүрүлүп, андагы бардык нерселер өчүрүлөт."</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили өчүрүлүп, андагы бардык нерселер өчүрүлөт."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин планшетиңизди бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин телефонуңузду бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Дагы башка параметрлерди көрүү үчүн телефонуңуздун кулпусун ачыңыз"</string>
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index 5f83f45958e9..5d80da8cb9aa 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -25,8 +25,7 @@
android:focusable="true"
android:screenReaderFocusable="true"
android:stateListAnimator="@anim/control_state_list_animator"
- android:layout_marginLeft="@dimen/control_base_item_margin"
- android:layout_marginRight="@dimen/control_base_item_margin"
+ android:layout_marginStart="@dimen/control_spacing"
android:background="@drawable/control_background">
<ImageView
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 80b7d1f8970f..e40138e1f49c 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -80,8 +80,8 @@
<ImageView
android:id="@+id/wallet_button"
- android:layout_height="@dimen/keyguard_affordance_height"
- android:layout_width="@dimen/keyguard_affordance_width"
+ android:layout_height="@dimen/keyguard_affordance_wallet_height"
+ android:layout_width="@dimen/keyguard_affordance_wallet_width"
android:layout_gravity="bottom|end"
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
diff --git a/packages/SystemUI/res/layout/udfps_enroll_view.xml b/packages/SystemUI/res/layout/udfps_enroll_view.xml
index a55653e5485f..f1ff6d669256 100644
--- a/packages/SystemUI/res/layout/udfps_enroll_view.xml
+++ b/packages/SystemUI/res/layout/udfps_enroll_view.xml
@@ -24,5 +24,6 @@
<ImageView
android:id="@+id/udfps_enroll_animation_fp_view"
android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_fingerprint_label"/>
</com.android.systemui.biometrics.UdfpsEnrollView>
diff --git a/packages/SystemUI/res/layout/wallet_empty_state.xml b/packages/SystemUI/res/layout/wallet_empty_state.xml
index cc2e781a8f13..d41679a5b416 100644
--- a/packages/SystemUI/res/layout/wallet_empty_state.xml
+++ b/packages/SystemUI/res/layout/wallet_empty_state.xml
@@ -22,7 +22,7 @@
android:id="@+id/wallet_empty_state"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginHorizontal="16dp"
+ android:layout_marginHorizontal="48dp"
android:layout_marginTop="48dp"
android:background="@drawable/wallet_empty_state_bg"
android:orientation="vertical"
diff --git a/packages/SystemUI/res/layout/wallet_fullscreen.xml b/packages/SystemUI/res/layout/wallet_fullscreen.xml
index aceefeecad5a..71006f08e8fa 100644
--- a/packages/SystemUI/res/layout/wallet_fullscreen.xml
+++ b/packages/SystemUI/res/layout/wallet_fullscreen.xml
@@ -54,9 +54,12 @@
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/Wallet.TextAppearance"
+ android:layout_marginHorizontal="48dp"
+ android:textColor="?androidprv:attr/textColorPrimary"
android:textAlignment="center"/>
+ <include layout="@layout/wallet_empty_state"/>
+
<com.android.systemui.wallet.ui.WalletCardCarousel
android:id="@+id/card_carousel"
android:layout_width="match_parent"
@@ -97,8 +100,6 @@
android:layout_marginVertical="24dp"/>
</LinearLayout>
- <include layout="@layout/wallet_empty_state"/>
-
<TextView
android:id="@+id/error_view"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index bd9e64b5efe1..d3401f89d846 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1079,7 +1079,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"إزالة من المفضّلة"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"نقل إلى الموضع <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"عناصر التحكّم"</string>
- <string name="controls_favorite_subtitle" msgid="6481675111056961083">"اختيار عناصر التحكّم التي يتم الوصول إليها من \"الإعدادات السريعة\"."</string>
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"اختَر عناصر التحكّم التي يتم الوصول إليها من \"الإعدادات السريعة\"."</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"اضغط مع الاستمرار واسحب لإعادة ترتيب عناصر التحكّم."</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"تمت إزالة كل عناصر التحكّم."</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"لم يتم حفظ التغييرات."</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 0beb96c6294d..853e00fe1ad7 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -39,7 +39,7 @@
<string name="battery_saver_start_action" msgid="4553256017945469937">"Batareya Qənaətini aktiv edin"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"Ayarlar"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
- <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ekran avtodönüşü"</string>
+ <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ekranın avtomatik dönməsi"</string>
<string name="status_bar_settings_mute_label" msgid="914392730086057522">"SUSDUR"</string>
<string name="status_bar_settings_auto_brightness_label" msgid="2151934479226017725">"AVTO"</string>
<string name="status_bar_settings_notifications" msgid="5285316949980621438">"Bildirişlər"</string>
@@ -343,7 +343,7 @@
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiv edilir..."</string>
<string name="quick_settings_brightness_label" msgid="680259653088849563">"Parlaqlıq"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avtodönüş"</string>
- <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekran avtodönüşü"</string>
+ <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranın avtomatik dönməsi"</string>
<string name="accessibility_quick_settings_rotation_value" msgid="2916484894750819251">"<xliff:g id="ID_1">%s</xliff:g> rejimi"</string>
<string name="quick_settings_rotation_locked_label" msgid="4420863550666310319">"Fırlanma kilidlidir"</string>
<string name="quick_settings_rotation_locked_portrait_label" msgid="1194988975270484482">"Portret"</string>
@@ -509,7 +509,7 @@
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"Bu funksiyanı təmin edən xidmətin yazma və ya yayım zamanı ekranda görünən və ya cihazdan oxudulan bütün bilgilərə girişi olacaq. Buraya parollar, ödəniş detalları, fotolar, mesajlar və oxudulan audio kimi məlumatlar daxildir."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Yazma və ya yayımlama başladılsın?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilə yazma və ya yayımlama başladılsın?"</string>
- <string name="media_projection_remember_text" msgid="6896767327140422951">"Daha göstərmə"</string>
+ <string name="media_projection_remember_text" msgid="6896767327140422951">"Göstərilməsin"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"Hamısını silin"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"İdarə edin"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Tarixçə"</string>
@@ -929,7 +929,7 @@
<string name="accessibility_quick_settings_not_available" msgid="6860875849497473854">"<xliff:g id="REASON">%s</xliff:g> səbəbi ilə əlçatan deyil"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını açın."</string>
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Ayarların sıralanmasını redaktə edin."</string>
- <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Yandırıb-söndürmə menyusu"</string>
+ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Qidalanma düyməsi menyusu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran kilidi"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"İstiliyə görə telefon söndü"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a86532d18226..75bc1132fff0 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1129,7 +1129,7 @@
<string name="new_story_status" msgid="9012195158584846525">"Нова история"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> сподели нова история"</string>
<string name="video_status" msgid="4548544654316843225">"Гледате"</string>
- <string name="audio_status" msgid="4237055636967709208">"Слуша се"</string>
+ <string name="audio_status" msgid="4237055636967709208">"Слушате"</string>
<string name="game_status" msgid="1340694320630973259">"Играете"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Приятели"</string>
<string name="empty_status" msgid="5938893404951307749">"Да поговорим!"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 2a9d7f529572..11dfe71522b0 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -520,7 +520,7 @@
<string name="manage_notifications_text" msgid="6885645344647733116">"Spravovat"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historie"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Nové"</string>
- <string name="notification_section_header_gentle" msgid="6804099527336337197">"Tiché"</string>
+ <string name="notification_section_header_gentle" msgid="6804099527336337197">"Ticho"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Oznámení"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzace"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazat všechna tichá oznámení"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a2db1f1562a1..909dddac80ac 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -798,7 +798,7 @@
<item quantity="other">%d minutos</item>
<item quantity="one">%d minuto</item>
</plurals>
- <string name="battery_panel_title" msgid="5931157246673665963">"Uso de la batería"</string>
+ <string name="battery_panel_title" msgid="5931157246673665963">"Uso de batería"</string>
<string name="battery_detail_charging_summary" msgid="8821202155297559706">"Ahorro de batería no disponible mientras se carga el dispositivo"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Ahorro de batería"</string>
<string name="battery_detail_switch_summary" msgid="3668748557848025990">"Reduce el rendimiento y los datos en segundo plano"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 2517960ee4ac..d48beba6ab08 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -728,7 +728,7 @@
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desaktibatu jakinarazpenak"</string>
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Aplikazio honen jakinarazpenak erakusten jarraitzea nahi duzu?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Isila"</string>
- <string name="notification_alert_title" msgid="3656229781017543655">"Balio lehenetsia"</string>
+ <string name="notification_alert_title" msgid="3656229781017543655">"Lehenetsia"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatikoa"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ez du tonurik jotzen edo dar-dar egiten"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ez du tonurik jotzen edo dar-dar egiten, eta elkarrizketaren atalaren behealdean agertzen da"</string>
@@ -1130,7 +1130,7 @@
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak istorio berri bat partekatu du"</string>
<string name="video_status" msgid="4548544654316843225">"Ikusten"</string>
<string name="audio_status" msgid="4237055636967709208">"Entzuten"</string>
- <string name="game_status" msgid="1340694320630973259">"Erreproduzitzen"</string>
+ <string name="game_status" msgid="1340694320630973259">"Jolasten"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Lagunak"</string>
<string name="empty_status" msgid="5938893404951307749">"Txatea dezagun gaur gauean!"</string>
<string name="status_before_loading" msgid="1500477307859631381">"Laster agertuko da edukia"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 3f3831f65948..805695b0c68e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1055,7 +1055,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"poista suosikeista"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Siirrä kohtaan <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Säätimet"</string>
- <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Valitse ohjaimet, joita käytetään pika-asetuksista"</string>
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Valitse säätimet, joita käytetään pika-asetuksista"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Järjestele säätimiä koskettamalla pitkään ja vetämällä"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Kaikki säätimet poistettu"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Muutoksia ei tallennettu"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index f279268a4ab8..5710c50fe1dc 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1122,14 +1122,14 @@
<string name="birthday_status_content_description" msgid="682836371128282925">"C\'est l\'anniversaire de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Anniversaire à venir"</string>
<string name="upcoming_birthday_status_content_description" msgid="2165036816803797148">"C\'est bientôt l\'anniversaire de <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="anniversary_status" msgid="1790034157507590838">"Fête"</string>
+ <string name="anniversary_status" msgid="1790034157507590838">"Anniversaire"</string>
<string name="anniversary_status_content_description" msgid="8212171790843327442">"C\'est l\'anniversaire de mariage de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Partage sa position"</string>
<string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> partage sa position"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nouvelle story"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> a partagé une story"</string>
<string name="video_status" msgid="4548544654316843225">"Regarde une vidéo"</string>
- <string name="audio_status" msgid="4237055636967709208">"Écoute"</string>
+ <string name="audio_status" msgid="4237055636967709208">"Écoute du contenu"</string>
<string name="game_status" msgid="1340694320630973259">"Joue"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amis"</string>
<string name="empty_status" msgid="5938893404951307749">"Chattez ce soir !"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 07a691cfea81..6230687b273e 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -487,7 +487,7 @@
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Comezar de novo"</string>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Si, continuar"</string>
<string name="guest_notification_title" msgid="4434456703930764167">"Usuario convidado"</string>
- <string name="guest_notification_text" msgid="4202692942089571351">"Para eliminar aplicacións e datos, quita o usuario invitado"</string>
+ <string name="guest_notification_text" msgid="4202692942089571351">"Para eliminar aplicacións e datos, quita o usuario convidado"</string>
<string name="guest_notification_remove_action" msgid="4153019027696868099">"QUITAR CONVIDADO"</string>
<string name="user_logout_notification_title" msgid="3644848998053832589">"Pechar sesión do usuario"</string>
<string name="user_logout_notification_text" msgid="7441286737342997991">"Pechar sesión do usuario actual"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index f7a1c8e0f025..adc01b8c4eb9 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -387,7 +387,7 @@
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"વપરાશકર્તા સેટિંગ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"થઈ ગયું"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"બંધ કરો"</string>
- <string name="quick_settings_connected" msgid="3873605509184830379">"કનેક્ટ થયેલ"</string>
+ <string name="quick_settings_connected" msgid="3873605509184830379">"કનેક્ટ થયેલું"</string>
<string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"કનેક્ટ કરેલ, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string>
<string name="quick_settings_connecting" msgid="2381969772953268809">"કનેક્ટ કરી રહ્યું છે..."</string>
<string name="quick_settings_tethering_label" msgid="5257299852322475780">"ટિથરિંગ"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 73a32d301836..1b48c098360c 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1126,7 +1126,7 @@
<string name="anniversary_status_content_description" msgid="8212171790843327442">"Այսօր <xliff:g id="NAME">%1$s</xliff:g>-ի տարեդարձն է"</string>
<string name="location_status" msgid="1294990572202541812">"Տեղադրության ցուցադրում"</string>
<string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը հայտնում է իր տեղադրության մասին տվյալները"</string>
- <string name="new_story_status" msgid="9012195158584846525">"Նոր հոդված"</string>
+ <string name="new_story_status" msgid="9012195158584846525">"Նոր պատմություն"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը նոր պատմություն է հրապարակել"</string>
<string name="video_status" msgid="4548544654316843225">"Տեսանյութ եմ դիտում"</string>
<string name="audio_status" msgid="4237055636967709208">"Բան եմ լսում"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index ce2a991798e0..a7cdfc1b1d73 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -65,7 +65,7 @@
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"‏למשתמש המחובר לחשבון במכשיר הזה אין אפשרות להפעיל ניפוי באגים ב-USB. כדי להשתמש בתכונה הזו יש לעבור אל המשתמש הראשי."</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"לאשר ניפוי באגים אלחוטי ברשת הזו?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"‏שם הרשת (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nכתובת Wi‑Fi‏ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
- <string name="wifi_debugging_always" msgid="2968383799517975155">"אפשר תמיד ברשת הזו"</string>
+ <string name="wifi_debugging_always" msgid="2968383799517975155">"לאשר תמיד ברשת הזו"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"אישור"</string>
<string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"אין הרשאה לניפוי באגים אלחוטי"</string>
<string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"למשתמש המחובר לחשבון במכשיר הזה אין אפשרות להפעיל ניפוי באגים אלחוטי. כדי להשתמש בתכונה הזו, יש לעבור אל המשתמש הראשי."</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index d12c4dc7aa5c..bbd4ff23c7d7 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -746,7 +746,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Әңгіме туралы хабарландырулардың жоғарғы жағында тұрады және құлыптаулы экранда профиль суреті ретінде көрсетіледі, қалқымалы анықтама ретінде шығады, \"Мазаламау\" режимін тоқтатады."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Параметрлер"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маңызды"</string>
- <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгімелесу функцияларын қолдамайды."</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгіме функцияларын қолдамайды."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Прокси-сервер арқылы жіберілген хабарландыру"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index d5557b9e363f..5ab4fe7e5d0e 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1128,7 +1128,7 @@
<string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಸ್ಥಳವನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತಿದ್ದಾರೆ"</string>
<string name="new_story_status" msgid="9012195158584846525">"ಹೊಸ ಸುದ್ದಿ"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಹೊಸ ಸ್ಟೋರಿಯನ್ನು ಹಂಚಿಕೊಂಡಿದ್ದಾರೆ"</string>
- <string name="video_status" msgid="4548544654316843225">"ವೀಕ್ಷಿಸುತ್ತಿರುವವರು"</string>
+ <string name="video_status" msgid="4548544654316843225">"ವೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="audio_status" msgid="4237055636967709208">"ಆಲಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="game_status" msgid="1340694320630973259">"ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="empty_user_name" msgid="3389155775773578300">"ಸ್ನೇಹಿತರು"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 8a4499f2134b..871061031aec 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -746,7 +746,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും കാണിക്കുന്നു, ഒരു ബബിൾ രൂപത്തിൽ ദൃശ്യമാകുന്നു, ശല്യപ്പെടുത്തരുത് മോഡ് തടസ്സപ്പെടുത്തുന്നു"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ക്രമീകരണം"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string>
- <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> സംഭാഷണ ഫീച്ചറുകളെ പിന്തുണയ്‌ക്കുന്നില്ല"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"സംഭാഷണ ഫീച്ചറുകളെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്‌ക്കുന്നില്ല"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"അറിയിപ്പുകളുടെ ഈ ഗ്രൂപ്പ് ഇവിടെ കോണ്‍ഫിഗര്‍ ചെയ്യാൻ കഴിയില്ല"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"പ്രോക്‌സി അറിയിപ്പ്"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 2a1506f9b2a7..09de767c2078 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1096,7 +1096,7 @@
<string name="controls_in_progress" msgid="4421080500238215939">"प्रगतीपथावर आहे"</string>
<string name="controls_added_tooltip" msgid="5866098408470111984">"नवीन नियंत्रणे पाहण्यासाठी क्विक सेटिंग्ज उघडा"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"नियंत्रणे जोडा"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"नियंत्रणे व्यवस्थापित करा"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"नियंत्रणे संपादित करा"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट जोडा"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"गट"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिव्हाइस निवडले"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 24bafa8eefef..165d8c033556 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1042,7 +1042,7 @@
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Alihkan ke tepi dan tunjukkan"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"togol"</string>
<string name="quick_controls_title" msgid="7095074621086860062">"Kawalan rumah"</string>
- <string name="controls_providers_title" msgid="6879775889857085056">"Pilih apl untuk menambah kawalan"</string>
+ <string name="controls_providers_title" msgid="6879775889857085056">"Pilih apl untuk menambahkan kawalan"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> kawalan ditambah.</item>
<item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> kawalan ditambah.</item>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 11e497d8fc78..ba63fc334149 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1096,7 +1096,7 @@
<string name="controls_in_progress" msgid="4421080500238215939">"ဆောင်ရွက်နေသည်"</string>
<string name="controls_added_tooltip" msgid="5866098408470111984">"ထိန်းချုပ်မှုအသစ်များ ကြည့်ရန် အမြန် ဆက်တင်များကို ဖွင့်ပါ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ထိန်းချုပ်မှုများ ထည့်ရန်"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"ထိန်းချုပ်မှုများ တည်းဖြတ်ရန်"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"ထိန်းချုပ်မှုများ ပြင်ရန်"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"မီဒီယာအထွက်များ ထည့်ရန်"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"အုပ်စု"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"စက်ပစ္စည်း ၁ ခုကို ရွေးချယ်ထားသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index c23e4795c7f4..28bd4031f6bb 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4811759950673118541">"Sys.gr.snitt"</string>
+ <string name="app_label" msgid="4811759950673118541">"System-UI"</string>
<string name="status_bar_clear_all_button" msgid="2491321682873657397">"Fjern"</string>
<string name="status_bar_no_notifications_title" msgid="7812479124981107507">"Ingen varslinger"</string>
<string name="status_bar_ongoing_events_title" msgid="3986169317496615446">"Aktiviteter"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index d25b38a5a7dd..ea74b72ed9e9 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -83,7 +83,7 @@
<string name="screenshot_saved_title" msgid="8893267638659083153">"स्क्रिनसट सेभ गरियो"</string>
<string name="screenshot_saved_text" msgid="7778833104901642442">"आफ्नो स्क्रिनसट हेर्न ट्याप गर्नुहोस्"</string>
<string name="screenshot_failed_title" msgid="3259148215671936891">"स्क्रिनसट सुरक्षित गर्न सकिएन"</string>
- <string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"यन्त्र अनलक गरेपछि मात्र स्क्रिनसट सुरक्षित गर्न सकिन्छ"</string>
+ <string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"डिभाइस अनलक गरेपछि मात्र स्क्रिनसट सुरक्षित गर्न सकिन्छ"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रिनसट फेरि लिएर हेर्नुहोस्"</string>
<string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"स्क्रिनसट सुरक्षित गर्न सकिएन"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"उक्त एप वा तपाईंको संगठनले स्क्रिनसटहरू लिन दिँदैन"</string>
@@ -730,8 +730,8 @@
<string name="notification_silence_title" msgid="8608090968400832335">"साइलेन्ट"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"डिफल्ट"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"स्वचालित"</string>
- <string name="notification_channel_summary_low" msgid="4860617986908931158">"न घन्टी बज्छ न त कम्पन नै हुन्छ"</string>
- <string name="notification_conversation_summary_low" msgid="1734433426085468009">"न घन्टी बज्छ न त कम्पन नै हुन्छ र वार्तालाप खण्डको तलतिर देखा पर्छ"</string>
+ <string name="notification_channel_summary_low" msgid="4860617986908931158">"बज्दैन पनि, भाइब्रेट पनि हुँदैन"</string>
+ <string name="notification_conversation_summary_low" msgid="1734433426085468009">"बज्दैन पनि, भाइब्रेट पनि हुँदैन र वार्तालाप खण्डको तलतिर देखा पर्छ"</string>
<string name="notification_channel_summary_default" msgid="3282930979307248890">"फोनको सेटिङका आधारमा घन्टी बज्न वा भाइब्रेट हुन सक्छ"</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फोनको सेटिङका आधारमा घन्टी बज्न वा भाइब्रेट हुन सक्छ। <xliff:g id="APP_NAME">%1$s</xliff:g> का वार्तालापहरू डिफल्ट रूपमा बबलमा देखाइन्छन्।"</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"फ्लोटिङ सर्टकटमार्फत यो सामग्रीतर्फ तपाईंको ध्यान आकर्षित गर्दछ।"</string>
@@ -1124,7 +1124,7 @@
<string name="upcoming_birthday_status_content_description" msgid="2165036816803797148">"<xliff:g id="NAME">%1$s</xliff:g> को जन्मदिन चाँडै आउँदै छ"</string>
<string name="anniversary_status" msgid="1790034157507590838">"वार्षिकोत्सव"</string>
<string name="anniversary_status_content_description" msgid="8212171790843327442">"आज <xliff:g id="NAME">%1$s</xliff:g> को वार्षिकोत्सव हो"</string>
- <string name="location_status" msgid="1294990572202541812">"स्थानसम्बन्धी जानकारी सेयर गरिँदै छ"</string>
+ <string name="location_status" msgid="1294990572202541812">"लोकेसन सेयर गरिँदै छ"</string>
<string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> आफ्नो स्थानसम्बन्धी जानकारी सेयर गर्दै हुनुहुन्छ"</string>
<string name="new_story_status" msgid="9012195158584846525">"नयाँ स्टोरी"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ले एउटा नयाँ स्टोरी सेयर गर्नुभयो"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8217c845fb96..9eae3d4a9498 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -727,13 +727,13 @@
<string name="inline_block_button" msgid="479892866568378793">"Zablokuj"</string>
<string name="inline_keep_button" msgid="299631874103662170">"Pokazuj nadal"</string>
<string name="inline_minimize_button" msgid="1474436209299333445">"Minimalizuj"</string>
- <string name="inline_silent_button_silent" msgid="525243786649275816">"Bez dźwięku"</string>
+ <string name="inline_silent_button_silent" msgid="525243786649275816">"Ciche"</string>
<string name="inline_silent_button_stay_silent" msgid="2129254868305468743">"Zachowaj wyciszenie"</string>
<string name="inline_silent_button_alert" msgid="5705343216858250354">"Alerty"</string>
<string name="inline_silent_button_keep_alerting" msgid="6577845442184724992">"Powiadamiaj dalej"</string>
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"Wyłącz powiadomienia"</string>
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Nadal pokazywać powiadomienia z tej aplikacji?"</string>
- <string name="notification_silence_title" msgid="8608090968400832335">"Bez dźwięku"</string>
+ <string name="notification_silence_title" msgid="8608090968400832335">"Ciche"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Domyślne"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatycznie"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Brak dźwięku i wibracji"</string>
@@ -751,7 +751,7 @@
<string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekran blokady, przerywa działanie trybu Nie przeszkadzać"</string>
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekran blokady, jako dymek, przerywa działanie trybu Nie przeszkadzać"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ustawienia"</string>
- <string name="notification_priority_title" msgid="2079708866333537093">"Priorytet"</string>
+ <string name="notification_priority_title" msgid="2079708866333537093">"Priorytetowe"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Tej grupy powiadomień nie można tu skonfigurować"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 267c308549e6..0abe4a009439 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1135,8 +1135,8 @@
<string name="new_story_status" msgid="9012195158584846525">"Subiect nou"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> a trimis o poveste nouă"</string>
<string name="video_status" msgid="4548544654316843225">"Urmăresc"</string>
- <string name="audio_status" msgid="4237055636967709208">"Se ascultă"</string>
- <string name="game_status" msgid="1340694320630973259">"Se redă"</string>
+ <string name="audio_status" msgid="4237055636967709208">"Ascult"</string>
+ <string name="game_status" msgid="1340694320630973259">"Mă joc"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Prieteni"</string>
<string name="empty_status" msgid="5938893404951307749">"Conversăm prin chat diseară?"</string>
<string name="status_before_loading" msgid="1500477307859631381">"Conținutul va apărea în curând"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f006722f58dd..ad33b0d3b730 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1136,13 +1136,13 @@
<string name="upcoming_birthday_status_content_description" msgid="2165036816803797148">"<xliff:g id="NAME">%1$s</xliff:g> má čoskoro narodeniny"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Výročie"</string>
<string name="anniversary_status_content_description" msgid="8212171790843327442">"<xliff:g id="NAME">%1$s</xliff:g> má výročie"</string>
- <string name="location_status" msgid="1294990572202541812">"Zdieľa sa poloha"</string>
+ <string name="location_status" msgid="1294990572202541812">"Zdieľam polohu"</string>
<string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> zdieľa polohu"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nová správa"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> zdieľal(a) nový príbeh"</string>
- <string name="video_status" msgid="4548544654316843225">"Pozerá sa video"</string>
+ <string name="video_status" msgid="4548544654316843225">"Pozerám video"</string>
<string name="audio_status" msgid="4237055636967709208">"Počúvam"</string>
- <string name="game_status" msgid="1340694320630973259">"Hrá sa hra"</string>
+ <string name="game_status" msgid="1340694320630973259">"Hrám hru"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Priatelia"</string>
<string name="empty_status" msgid="5938893404951307749">"Poďme sa rozprávať."</string>
<string name="status_before_loading" msgid="1500477307859631381">"Obsah sa čoskoro zobrazí"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 94a16ad338b5..d7a5efa0f4bf 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -777,7 +777,7 @@
<string name="inline_undo" msgid="9026953267645116526">"Zhbëj"</string>
<string name="demote" msgid="6225813324237153980">"Shëno se ky njoftim nuk është një bisedë"</string>
<string name="notification_conversation_favorite" msgid="1905240206975921907">"Bashkëbisedim i rëndësishëm"</string>
- <string name="notification_conversation_unfavorite" msgid="181383708304763807">"Nuk është bashkëbisedim i rëndësishëm"</string>
+ <string name="notification_conversation_unfavorite" msgid="181383708304763807">"Nuk është bisedë e rëndësishme"</string>
<string name="notification_conversation_mute" msgid="268951550222925548">"Në heshtje"</string>
<string name="notification_conversation_unmute" msgid="2692255619510896710">"Po sinjalizon"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"Shfaq flluskën"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index fa6952c9e117..ac8c44f27b6d 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1124,13 +1124,13 @@
<string name="upcoming_birthday_status_content_description" msgid="2165036816803797148">"Siku ya kuzaliwa ya <xliff:g id="NAME">%1$s</xliff:g> inakaribia"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Maadhimisho"</string>
<string name="anniversary_status_content_description" msgid="8212171790843327442">"Ni maadhimisho ya <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="location_status" msgid="1294990572202541812">"Inashiriki mahali"</string>
+ <string name="location_status" msgid="1294990572202541812">"Unashiriki mahali"</string>
<string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> anashiriki maelezo ya mahali"</string>
<string name="new_story_status" msgid="9012195158584846525">"Habari mpya"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ameshiriki hadithi mpya"</string>
<string name="video_status" msgid="4548544654316843225">"Unatazama"</string>
- <string name="audio_status" msgid="4237055636967709208">"Inasikiliza"</string>
- <string name="game_status" msgid="1340694320630973259">"Inacheza"</string>
+ <string name="audio_status" msgid="4237055636967709208">"Unasikiliza"</string>
+ <string name="game_status" msgid="1340694320630973259">"Unacheza"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Marafiki"</string>
<string name="empty_status" msgid="5938893404951307749">"Tupige gumzo usiku!"</string>
<string name="status_before_loading" msgid="1500477307859631381">"Maudhui yataonekana hivi karibuni"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 3be73ba8df25..9f8e6364e55d 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -68,8 +68,6 @@
phone hints. -->
<dimen name="edge_tap_area_width">80dp</dimen>
- <dimen name="keyguard_indication_margin_bottom">90dp</dimen>
-
<!-- Margin on the right side of the system icon group on Keyguard. -->
<dimen name="system_icons_keyguard_padding_end">2dp</dimen>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 900277a2cdb3..ea22e5ba94b7 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1124,12 +1124,12 @@
<string name="upcoming_birthday_status_content_description" msgid="2165036816803797148">"<xliff:g id="NAME">%1$s</xliff:g> పుట్టినరోజు త్వరలో రాబోతోంది"</string>
<string name="anniversary_status" msgid="1790034157507590838">"వార్షికోత్సవం"</string>
<string name="anniversary_status_content_description" msgid="8212171790843327442">"ఇది <xliff:g id="NAME">%1$s</xliff:g> వార్షికోత్సవం"</string>
- <string name="location_status" msgid="1294990572202541812">"లొకేషన్ షేరింగ్"</string>
+ <string name="location_status" msgid="1294990572202541812">"లొకేషన్ షేర్ ఔతోంది"</string>
<string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> లొకేషన్‌ను షేర్ చేస్తోంది"</string>
<string name="new_story_status" msgid="9012195158584846525">"కొత్త కథనం"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> కొత్త కథనాన్ని షేర్ చేసింది"</string>
<string name="video_status" msgid="4548544654316843225">"చూస్తున్నారు"</string>
- <string name="audio_status" msgid="4237055636967709208">"వినడం"</string>
+ <string name="audio_status" msgid="4237055636967709208">"వింటున్నారు"</string>
<string name="game_status" msgid="1340694320630973259">"ఆడుతున్నారు"</string>
<string name="empty_user_name" msgid="3389155775773578300">"ఫ్రెండ్స్"</string>
<string name="empty_status" msgid="5938893404951307749">"రాత్రి చాట్ చేద్దాం!"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4fd84a1f9ce5..ae3d16b8f919 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -745,7 +745,7 @@
<string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Görüşme bildirimlerinin üstünde ve kilit ekranında profil resmi olarak gösterilir, Rahatsız Etmeyin\'i kesintiye uğratır"</string>
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Görüşme bildirimlerinin üstünde ve kilit ekranında profil resmi olarak gösterilir, baloncuk olarak görünür, Rahatsız Etmeyin\'i kesintiye uğratır"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
- <string name="notification_priority_title" msgid="2079708866333537093">"Öncelik"</string>
+ <string name="notification_priority_title" msgid="2079708866333537093">"Öncelikli"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>, sohbet özelliklerini desteklemiyor"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildirim grubu burada yapılandırılamaz"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 4ca003d8ada6..cf66b91ccd16 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -746,7 +746,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"یہ گفتگو کی اطلاعات کے اوپری حصّے پر اور مقفل اسکرین پر پروفائل کی تصویر کے بطور دکھائی دیتا ہے، بلبلے کے بطور ظاہر ہوتا ہے، \'ڈسٹرب نہ کریں\' میں مداخلت کرتا ہے"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ترتیبات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string>
- <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> گفتگو کی خصوصیات کو سپورٹ نہیں کرتا ہے"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ گفتگو کی خصوصیات کو سپورٹ نہیں کرتی ہے"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"اطلاعات کے اس گروپ کو یہاں کنفیگر نہیں کیا جا سکتا"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"پراکسی اطلاع"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 7b4c5d9a0f9b..2cd285917b9d 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1128,9 +1128,9 @@
<string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> joylashuvni ulashmoqda"</string>
<string name="new_story_status" msgid="9012195158584846525">"Yangi hikoya"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> yangi hikoyani ulashdi"</string>
- <string name="video_status" msgid="4548544654316843225">"Tomosha"</string>
- <string name="audio_status" msgid="4237055636967709208">"Gapiring"</string>
- <string name="game_status" msgid="1340694320630973259">"Ijro etilmoqda"</string>
+ <string name="video_status" msgid="4548544654316843225">"Tomosha qilmoqda"</string>
+ <string name="audio_status" msgid="4237055636967709208">"Tinglamoqda"</string>
+ <string name="game_status" msgid="1340694320630973259">"Oʻynamoqda"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Doʻstlar"</string>
<string name="empty_status" msgid="5938893404951307749">"Bugun yozishaylik!"</string>
<string name="status_before_loading" msgid="1500477307859631381">"Kontent tezda chiqadi"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 681430b82334..19eeb8a97ae9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1129,7 +1129,7 @@
<string name="new_story_status" msgid="9012195158584846525">"新故事"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g>分享了一个新故事"</string>
<string name="video_status" msgid="4548544654316843225">"正在观看"</string>
- <string name="audio_status" msgid="4237055636967709208">"正在收听"</string>
+ <string name="audio_status" msgid="4237055636967709208">"正在听音频内容"</string>
<string name="game_status" msgid="1340694320630973259">"正在玩游戏"</string>
<string name="empty_user_name" msgid="3389155775773578300">"好友"</string>
<string name="empty_status" msgid="5938893404951307749">"今晚来聊聊吧!"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 47ffed04adbe..481b92c130ca 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1124,12 +1124,12 @@
<string name="upcoming_birthday_status_content_description" msgid="2165036816803797148">"<xliff:g id="NAME">%1$s</xliff:g>的生日快到了"</string>
<string name="anniversary_status" msgid="1790034157507590838">"週年紀念"</string>
<string name="anniversary_status_content_description" msgid="8212171790843327442">"今天是<xliff:g id="NAME">%1$s</xliff:g>的週年紀念"</string>
- <string name="location_status" msgid="1294990572202541812">"分享位置資訊"</string>
+ <string name="location_status" msgid="1294990572202541812">"正在分享位置"</string>
<string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g>正在分享位置"</string>
- <string name="new_story_status" msgid="9012195158584846525">"最新報導"</string>
+ <string name="new_story_status" msgid="9012195158584846525">"新故事"</string>
<string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g>分享了新的動態消息"</string>
- <string name="video_status" msgid="4548544654316843225">"正在觀看"</string>
- <string name="audio_status" msgid="4237055636967709208">"正在聽取音訊"</string>
+ <string name="video_status" msgid="4548544654316843225">"正在觀看影片"</string>
+ <string name="audio_status" msgid="4237055636967709208">"正在收聽音訊"</string>
<string name="game_status" msgid="1340694320630973259">"正在玩遊戲"</string>
<string name="empty_user_name" msgid="3389155775773578300">"朋友"</string>
<string name="empty_status" msgid="5938893404951307749">"今晚傾下偈啦!"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 1f6a94d254b7..f64299dcd4c4 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -187,7 +187,6 @@
<!-- UDFPS colors -->
<color name="udfps_enroll_icon">#000000</color> <!-- 100% black -->
<color name="udfps_moving_target_fill">#cc4285f4</color> <!-- 80% blue -->
- <color name="udfps_moving_target_stroke">#ff669DF6</color> <!-- 100% blue -->
<color name="udfps_enroll_progress">#ff669DF6</color> <!-- 100% blue -->
<!-- Logout button -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1a0050373952..b4deaa0af543 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -99,7 +99,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- internet,wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast,screenrecord
+ internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle
</string>
<!-- The minimum number of tiles to display in QuickSettings -->
@@ -107,7 +107,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- internet,wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness,cameratoggle,mictoggle,controls,alarm,wallet
+ internet,wifi,cell,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 05f2f6727a73..0022039a78ca 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -771,6 +771,9 @@
<!-- Move distance for the unlock hint animation on the lockscreen -->
<dimen name="hint_move_distance">75dp</dimen>
+ <!-- The overshoot amount when the panel flings open -->
+ <dimen name="panel_overshoot_amount">16dp</dimen>
+
<!-- The width of the region on the left/right edge of the screen for performing the camera/
phone hints. -->
<dimen name="edge_tap_area_width">48dp</dimen>
@@ -892,6 +895,10 @@
<!-- The width/height of the keyguard bottom area icon view on keyguard. -->
<dimen name="keyguard_affordance_height">48dp</dimen>
<dimen name="keyguard_affordance_width">48dp</dimen>
+
+ <dimen name="keyguard_affordance_wallet_height">48dp</dimen>
+ <dimen name="keyguard_affordance_wallet_width">48dp</dimen>
+
<dimen name="keyguard_affordance_horizontal_offset">32dp</dimen>
<dimen name="keyguard_affordance_vertical_offset">32dp</dimen>
<!-- Value should be at least sum of 'keyguard_affordance_width' +
@@ -903,7 +910,7 @@
<dimen name="keyguard_lock_width">42dp</dimen>
<dimen name="keyguard_lock_padding">20dp</dimen>
- <dimen name="keyguard_indication_margin_bottom">40dp</dimen>
+ <dimen name="keyguard_indication_margin_bottom">32dp</dimen>
<!-- The text size for battery level -->
<dimen name="battery_level_text_size">12sp</dimen>
@@ -1324,15 +1331,15 @@
<dimen name="control_spinner_padding_horizontal">20dp</dimen>
<dimen name="control_text_size">14sp</dimen>
<dimen name="control_icon_size">24dp</dimen>
- <dimen name="control_spacing">4dp</dimen>
+ <dimen name="control_spacing">8dp</dimen>
<dimen name="control_list_divider">1dp</dimen>
- <dimen name="control_corner_radius">12dp</dimen>
- <dimen name="control_height">106dp</dimen>
+ <dimen name="control_corner_radius">14dp</dimen>
+ <dimen name="control_height">104dp</dimen>
<dimen name="control_padding">12dp</dimen>
<dimen name="control_padding_adjustment">4dp</dimen>
<dimen name="control_status_normal">14sp</dimen>
<dimen name="control_status_expanded">18sp</dimen>
- <dimen name="control_base_item_margin">2dp</dimen>
+ <dimen name="control_base_item_margin">4dp</dimen>
<dimen name="control_status_padding">3dp</dimen>
<fraction name="controls_toggle_bg_intensity">5%</fraction>
<fraction name="controls_dimmed_alpha">40%</fraction>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e2a49a1a7b2b..7f4e4751312e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1653,6 +1653,8 @@
<!-- Wallet strings -->
<!-- Wallet empty state, title [CHAR LIMIT=32] -->
<string name="wallet_title">Wallet</string>
+ <!-- Wallet empty state label. [CHAR LIMIT=NONE] -->
+ <string name="wallet_empty_state_label">Get set up to make faster, more secure purchases with your phone</string>
<!-- Label of the button at the bottom prompting user enter wallet app. [CHAR LIMIT=NONE] -->
<string name="wallet_app_button_label">Show all</string>
<!-- Label of the button underneath the card carousel prompting user unlock device. [CHAR LIMIT=NONE] -->
@@ -2819,9 +2821,17 @@
<string name="controls_media_resume">Resume</string>
<!-- Label for button to go to media control settings screen [CHAR_LIMIT=30] -->
<string name="controls_media_settings_button">Settings</string>
+ <!-- Description for media control's playing media item, including information for the media's title, the artist, and source app [CHAR LIMIT=NONE]-->
+ <string name="controls_media_playing_item_description"><xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> by <xliff:g id="artist_name" example="Various artists">%2$s</xliff:g> is playing from <xliff:g id="app_label" example="Spotify">%3$s</xliff:g></string>
<!-- Title for Smartspace recommendation card within media controls. The "Play" means the action to play a media [CHAR_LIMIT=10] -->
<string name="controls_media_smartspace_rec_title">Play</string>
+ <!-- Description for Smartspace recommendation card within media controls [CHAR_LIMIT=NONE] -->
+ <string name="controls_media_smartspace_rec_description">Open <xliff:g id="app_label" example="Spotify">%1$s</xliff:g></string>
+ <!-- Description for Smartspace recommendation's media item, including information for the media's title, the artist, and source app [CHAR LIMIT=NONE]-->
+ <string name="controls_media_smartspace_rec_item_description">Play <xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> by <xliff:g id="artist_name" example="Various artists">%2$s</xliff:g> from <xliff:g id="app_label" example="Spotify">%3$s</xliff:g></string>
+ <!-- Description for Smartspace recommendation's media item which doesn't have artist info, including information for the media's title and the source app [CHAR LIMIT=NONE]-->
+ <string name="controls_media_smartspace_rec_item_no_artist_description">Play <xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> from <xliff:g id="app_label" example="Spotify">%2$s</xliff:g></string>
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
<string name="controls_error_timeout">Inactive, check app</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index fbea1e9a594d..a7239cabcae5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -342,7 +342,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
}
- void refreshFormat(String timeFormat) {
+ void refreshFormat() {
if (mClockViewController != null) {
mClockViewController.refreshFormat();
mLargeClockViewController.refreshFormat();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index e8cc5c8a49f3..e4cabcb94ebe 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -287,6 +287,11 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
@Override
+ public void onTimeFormatChanged(String timeFormat) {
+ mKeyguardClockSwitchController.refreshFormat();
+ }
+
+ @Override
public void onTimeZoneChanged(TimeZone timeZone) {
mKeyguardClockSwitchController.updateTimeZone(timeZone);
}
@@ -313,6 +318,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
@Override
public void onUserSwitchComplete(int userId) {
+ mKeyguardClockSwitchController.refreshFormat();
mView.updateOwnerInfo();
mView.updateLogoutView(shouldShowLogout());
}
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index 9c5a40c22bd8..186917fc8807 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -46,6 +46,9 @@ public class LatencyTester extends SystemUI {
ACTION_FINGERPRINT_WAKE =
"com.android.systemui.latency.ACTION_FINGERPRINT_WAKE";
private static final String
+ ACTION_FACE_WAKE =
+ "com.android.systemui.latency.ACTION_FACE_WAKE";
+ private static final String
ACTION_TURN_ON_SCREEN =
"com.android.systemui.latency.ACTION_TURN_ON_SCREEN";
private final BiometricUnlockController mBiometricUnlockController;
@@ -70,13 +73,16 @@ public class LatencyTester extends SystemUI {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_FINGERPRINT_WAKE);
+ filter.addAction(ACTION_FACE_WAKE);
filter.addAction(ACTION_TURN_ON_SCREEN);
mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_FINGERPRINT_WAKE.equals(action)) {
- fakeWakeAndUnlock();
+ fakeWakeAndUnlock(BiometricSourceType.FINGERPRINT);
+ } else if (ACTION_FACE_WAKE.equals(action)) {
+ fakeWakeAndUnlock(BiometricSourceType.FACE);
} else if (ACTION_TURN_ON_SCREEN.equals(action)) {
fakeTurnOnScreen();
}
@@ -93,10 +99,9 @@ public class LatencyTester extends SystemUI {
SystemClock.uptimeMillis(), WAKE_REASON_UNKNOWN, "android.policy:LATENCY_TESTS");
}
- private void fakeWakeAndUnlock() {
- mBiometricUnlockController.onBiometricAcquired(BiometricSourceType.FINGERPRINT);
+ private void fakeWakeAndUnlock(BiometricSourceType type) {
+ mBiometricUnlockController.onBiometricAcquired(type);
mBiometricUnlockController.onBiometricAuthenticated(
- KeyguardUpdateMonitor.getCurrentUser(), BiometricSourceType.FINGERPRINT,
- true /* isStrongBiometric */);
+ KeyguardUpdateMonitor.getCurrentUser(), type, true /* isStrongBiometric */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 01fbe398f8b6..75373abc5124 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -110,7 +110,8 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
visibility = GONE
}
})
- vibrate()
+ // TODO (b/185124905): custom haptic TBD
+ // vibrate()
animatorSet.start()
visibility = VISIBLE
rippleInProgress = true
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index cef3e7de3478..dd339abb3a40 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -211,6 +211,12 @@ public class UdfpsController implements DozeReceiver {
}
}
+ void onAcquiredGood() {
+ if (mEnrollHelper != null) {
+ mEnrollHelper.animateIfLastStep();
+ }
+ }
+
void onEnrollmentHelp() {
if (mEnrollHelper != null) {
mEnrollHelper.onEnrollmentHelp();
@@ -260,6 +266,11 @@ public class UdfpsController implements DozeReceiver {
}
mGoodCaptureReceived = true;
mView.stopIllumination();
+ if (mServerRequest != null) {
+ mServerRequest.onAcquiredGood();
+ } else {
+ Log.e(TAG, "Null serverRequest when onAcquiredGood");
+ }
});
}
@@ -658,8 +669,7 @@ public class UdfpsController implements DozeReceiver {
// during a11y.
if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR
|| reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) {
- mView.setImportantForAccessibility(
- View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ mView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
mWindowManager.addView(mView, computeLayoutParams(animation));
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index 6b6e0f19d7fb..ea69b1d626ae 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -47,7 +47,6 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
@NonNull private final Drawable mMovingTargetFpIcon;
@NonNull private final Paint mSensorOutlinePaint;
@NonNull private final Paint mBlueFill;
- @NonNull private final Paint mBlueStroke;
@Nullable private RectF mSensorRect;
@Nullable private UdfpsEnrollHelper mEnrollHelper;
@@ -76,12 +75,6 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
mBlueFill.setColor(context.getColor(R.color.udfps_moving_target_fill));
mBlueFill.setStyle(Paint.Style.FILL);
- mBlueStroke = new Paint(0 /* flags */);
- mBlueStroke.setAntiAlias(true);
- mBlueStroke.setColor(context.getColor(R.color.udfps_moving_target_stroke));
- mBlueStroke.setStyle(Paint.Style.STROKE);
- mBlueStroke.setStrokeWidth(12);
-
mMovingTargetFpIcon = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
mMovingTargetFpIcon.setTint(Color.WHITE);
mMovingTargetFpIcon.mutate();
@@ -146,6 +139,10 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
}
}
+ void onLastStepAcquired() {
+ mProgressDrawable.onLastStepAcquired();
+ }
+
@Override
public void draw(@NonNull Canvas canvas) {
mProgressDrawable.draw(canvas);
@@ -163,7 +160,6 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
canvas.scale(mCurrentScale, mCurrentScale,
mSensorRect.centerX(), mSensorRect.centerY());
canvas.drawOval(mSensorRect, mBlueFill);
- canvas.drawOval(mSensorRect, mBlueStroke);
}
mMovingTargetFpIcon.draw(canvas);
@@ -188,7 +184,6 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
super.setAlpha(alpha);
mSensorOutlinePaint.setAlpha(alpha);
mBlueFill.setAlpha(alpha);
- mBlueStroke.setAlpha(alpha);
mMovingTargetFpIcon.setAlpha(alpha);
invalidateSelf();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 470fb8c1a561..412b77698159 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -21,8 +21,11 @@ import android.annotation.Nullable;
import android.content.Context;
import android.graphics.PointF;
import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.media.AudioAttributes;
import android.os.Build;
import android.os.UserHandle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
import android.provider.Settings;
import android.util.Log;
import android.util.TypedValue;
@@ -47,8 +50,15 @@ public class UdfpsEnrollHelper {
// Enroll with two center touches before going to guided enrollment
private static final int NUM_CENTER_TOUCHES = 2;
+ private static final AudioAttributes VIBRATION_SONFICATION_ATTRIBUTES =
+ new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .build();
+
interface Listener {
void onEnrollmentProgress(int remaining, int totalSteps);
+ void onLastStepAcquired();
}
@NonNull private final Context mContext;
@@ -56,6 +66,9 @@ public class UdfpsEnrollHelper {
private final int mEnrollReason;
private final boolean mAccessibilityEnabled;
@NonNull private final List<PointF> mGuidedEnrollmentPoints;
+ @NonNull private final Vibrator mVibrator;
+ @NonNull private final VibrationEffect mEffectClick =
+ VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
private int mTotalSteps = -1;
private int mRemainingSteps = -1;
@@ -69,6 +82,7 @@ public class UdfpsEnrollHelper {
public UdfpsEnrollHelper(@NonNull Context context, int reason) {
mContext = context;
mEnrollReason = reason;
+ mVibrator = context.getSystemService(Vibrator.class);
final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
mAccessibilityEnabled = am.isEnabled();
@@ -127,6 +141,7 @@ public class UdfpsEnrollHelper {
if (remaining != mRemainingSteps) {
mLocationsEnrolled++;
+ vibrateSuccess();
}
mRemainingSteps = remaining;
@@ -178,4 +193,20 @@ public class UdfpsEnrollHelper {
.get(index % mGuidedEnrollmentPoints.size());
return new PointF(originalPoint.x * scale, originalPoint.y * scale);
}
+
+ void animateIfLastStep() {
+ if (mListener == null) {
+ Log.e(TAG, "animateIfLastStep, null listener");
+ return;
+ }
+
+ if (mRemainingSteps <= 2 && mRemainingSteps >= 0) {
+ mListener.onLastStepAcquired();
+ vibrateSuccess();
+ }
+ }
+
+ private void vibrateSuccess() {
+ mVibrator.vibrate(mEffectClick, VIBRATION_SONFICATION_ATTRIBUTES);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index 5c9e52f86471..4195009937c2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -23,6 +23,7 @@ import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
+import android.util.Log;
import android.util.TypedValue;
import androidx.annotation.NonNull;
@@ -46,6 +47,8 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable {
@Nullable private ValueAnimator mProgressAnimator;
private float mProgress;
+ private int mRotation; // After last step, rotate the progress bar once
+ private boolean mLastStepAcquired;
public UdfpsEnrollProgressBarDrawable(@NonNull Context context,
@NonNull UdfpsEnrollDrawable parent) {
@@ -81,13 +84,34 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable {
// Add one so that the first steps actually changes progress, but also so that the last
// step ends at 1.0
final float progress = (totalSteps - remaining + 1) / (float) (totalSteps + 1);
+ setEnrollmentProgress(progress);
+ }
+
+ private void setEnrollmentProgress(float progress) {
+ if (mLastStepAcquired) {
+ return;
+ }
+
+ long animationDuration = 150;
+
+ if (progress == 1.f) {
+ animationDuration = 400;
+ final ValueAnimator rotationAnimator = ValueAnimator.ofInt(0, 400);
+ rotationAnimator.setDuration(animationDuration);
+ rotationAnimator.addUpdateListener(animation -> {
+ Log.d(TAG, "Rotation: " + mRotation);
+ mRotation = (int) animation.getAnimatedValue();
+ mParent.invalidateSelf();
+ });
+ rotationAnimator.start();
+ }
if (mProgressAnimator != null && mProgressAnimator.isRunning()) {
mProgressAnimator.cancel();
}
mProgressAnimator = ValueAnimator.ofFloat(mProgress, progress);
- mProgressAnimator.setDuration(150);
+ mProgressAnimator.setDuration(animationDuration);
mProgressAnimator.addUpdateListener(animation -> {
mProgress = (float) animation.getAnimatedValue();
// Use the parent to invalidate, since it's the one that's attached as the view's
@@ -99,12 +123,17 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable {
mProgressAnimator.start();
}
+ void onLastStepAcquired() {
+ setEnrollmentProgress(1.f);
+ mLastStepAcquired = true;
+ }
+
@Override
public void draw(@NonNull Canvas canvas) {
canvas.save();
// Progress starts from the top, instead of the right
- canvas.rotate(-90, getBounds().centerX(), getBounds().centerY());
+ canvas.rotate(-90 + mRotation, getBounds().centerX(), getBounds().centerY());
// Progress bar "background track"
final float halfPaddingPx = Utils.dpToPixels(mContext, PROGRESS_BAR_THICKNESS_DP) / 2;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
index 3b3022045849..7f4d7fe01e90 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
@@ -63,8 +63,10 @@ public class UdfpsEnrollView extends UdfpsAnimationView {
}
void onEnrollmentProgress(int remaining, int totalSteps) {
- mHandler.post(() -> {
- mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps);
- });
+ mHandler.post(() -> mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps));
+ }
+
+ void onLastStepAcquired() {
+ mHandler.post(mFingerprintDrawable::onLastStepAcquired);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index 953448d93d6a..91cc149be800 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -32,7 +32,17 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp
private final int mEnrollProgressBarRadius;
@NonNull private final UdfpsEnrollHelper mEnrollHelper;
@NonNull private final UdfpsEnrollHelper.Listener mEnrollHelperListener =
- mView::onEnrollmentProgress;
+ new UdfpsEnrollHelper.Listener() {
+ @Override
+ public void onEnrollmentProgress(int remaining, int totalSteps) {
+ mView.onEnrollmentProgress(remaining, totalSteps);
+ }
+
+ @Override
+ public void onLastStepAcquired() {
+ mView.onLastStepAcquired();
+ }
+ };
protected UdfpsEnrollViewController(
@NonNull UdfpsEnrollView view,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 9a32412ba241..750d42c0a848 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -62,7 +62,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
private boolean mQsExpanded;
private boolean mFaceDetectRunning;
private boolean mHintShown;
- private boolean mTransitioningFromHome;
private int mStatusBarState;
/**
@@ -112,11 +111,11 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mStatusBarState = mStatusBarStateController.getState();
mQsExpanded = mKeyguardViewManager.isQsExpanded();
mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
+ mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
updateAlpha();
updatePauseAuth();
mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
- mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
}
@Override
@@ -127,7 +126,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mStatusBarStateController.removeCallback(mStateListener);
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
- mTransitioningFromHome = false;
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
if (mCancelDelayedHintRunnable != null) {
@@ -141,7 +139,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
super.dump(fd, pw, args);
pw.println("mShowingUdfpsBouncer=" + mShowingUdfpsBouncer);
pw.println("mFaceDetectRunning=" + mFaceDetectRunning);
- pw.println("mTransitioningFromHomeToKeyguard=" + mTransitioningFromHome);
pw.println("mStatusBarState=" + StatusBarState.toShortString(mStatusBarState));
pw.println("mQsExpanded=" + mQsExpanded);
pw.println("mIsBouncerVisible=" + mIsBouncerVisible);
@@ -195,10 +192,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
return true;
}
- if (mTransitioningFromHome && mKeyguardViewMediator.isAnimatingScreenOff()) {
- return true;
- }
-
if (mQsExpanded) {
return true;
}
@@ -277,17 +270,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
public void onDozeAmountChanged(float linear, float eased) {
if (linear != 0) showUdfpsBouncer(false);
mView.onDozeAmountChanged(linear, eased);
- if (linear == 1f) {
- // transition has finished
- mTransitioningFromHome = false;
- }
- updatePauseAuth();
- }
-
- @Override
- public void onStatePreChange(int oldState, int newState) {
- mTransitioningFromHome = oldState == StatusBarState.SHADE
- && newState == StatusBarState.KEYGUARD;
updatePauseAuth();
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 821a171e883c..af7089296bca 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -399,6 +399,12 @@ class ControlsUiControllerImpl @Inject constructor (
val baseLayout = inflater.inflate(
R.layout.controls_base_item, lastRow, false) as ViewGroup
lastRow.addView(baseLayout)
+
+ // Use ConstraintLayout in the future... for now, manually adjust margins
+ if (lastRow.getChildCount() == 1) {
+ val lp = baseLayout.getLayoutParams() as ViewGroup.MarginLayoutParams
+ lp.setMarginStart(0)
+ }
val cvh = ControlViewHolder(
baseLayout,
controlsController.get(),
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index d698142674ce..4201411b168a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -71,12 +71,14 @@ import kotlin.Unit;
*/
public class MediaControlPanel {
private static final String TAG = "MediaControlPanel";
+
private static final float DISABLED_ALPHA = 0.38f;
private static final String EXTRAS_SMARTSPACE_INTENT =
"com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT";
- private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
private static final int MEDIA_RECOMMENDATION_ITEMS_PER_ROW = 3;
private static final int MEDIA_RECOMMENDATION_MAX_NUM = 6;
+ private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
+ private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
@@ -292,6 +294,12 @@ public class MediaControlPanel {
});
}
+ // Accessibility label
+ mPlayerViewHolder.getPlayer().setContentDescription(
+ mContext.getString(
+ R.string.controls_media_playing_item_description,
+ data.getSong(), data.getArtist(), data.getApp()));
+
ImageView albumView = mPlayerViewHolder.getAlbumView();
boolean hasArtwork = data.getArtwork() != null;
if (hasArtwork) {
@@ -330,7 +338,6 @@ public class MediaControlPanel {
}
// Song name
-
TextView titleText = mPlayerViewHolder.getTitleText();
titleText.setText(data.getSong());
@@ -497,8 +504,8 @@ public class MediaControlPanel {
mInstanceId = data.getTargetId().hashCode();
mBackgroundColor = data.getBackgroundColor();
- mRecommendationViewHolder.getRecommendations()
- .setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
+ TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();
+ recommendationCard.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
List<SmartspaceAction> mediaRecommendationList = data.getRecommendations();
if (mediaRecommendationList == null || mediaRecommendationList.isEmpty()) {
@@ -522,15 +529,17 @@ public class MediaControlPanel {
icon.setColorFilter(getGrayscaleFilter());
ImageView headerLogoImageView = mRecommendationViewHolder.getCardIcon();
headerLogoImageView.setImageDrawable(icon);
- // Set up media source app's label text. Fallback to "Play" if the found label is empty.
+ // Set up media source app's label text.
CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo);
if (appLabel.length() != 0) {
TextView headerTitleText = mRecommendationViewHolder.getCardText();
headerTitleText.setText(appLabel);
}
- // Set up media card's tap action if applicable.
- setSmartspaceRecItemOnClickListener(
- mRecommendationViewHolder.getRecommendations(), data.getCardAction());
+ // Set up media rec card's tap action if applicable.
+ setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction());
+ // Set up media rec card's accessibility label.
+ recommendationCard.setContentDescription(
+ mContext.getString(R.string.controls_media_smartspace_rec_description, appLabel));
List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems();
List<Integer> mediaCoverItemsResIds = mRecommendationViewHolder.getMediaCoverItemsResIds();
@@ -554,6 +563,21 @@ public class MediaControlPanel {
// Set up the media item's click listener if applicable.
setSmartspaceRecItemOnClickListener(mediaCoverImageView, recommendation);
+ // Set up the accessibility label for the media item.
+ String artistName = recommendation.getExtras()
+ .getString(KEY_SMARTSPACE_ARTIST_NAME, "");
+ if (artistName.isEmpty()) {
+ mediaCoverImageView.setContentDescription(
+ mContext.getString(
+ R.string.controls_media_smartspace_rec_item_no_artist_description,
+ recommendation.getTitle(), appLabel));
+ } else {
+ mediaCoverImageView.setContentDescription(
+ mContext.getString(
+ R.string.controls_media_smartspace_rec_item_description,
+ recommendation.getTitle(), artistName, appLabel));
+ }
+
if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) {
setVisibleAndAlpha(collapsedSet,
mediaCoverItemsResIds.get(uiComponentIndex), true);
diff --git a/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java b/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java
index a5c239244c10..b5ac90828fce 100644
--- a/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java
@@ -31,12 +31,14 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
/** Helper functions to handle notifications in People Tiles. */
@@ -234,5 +236,13 @@ public class NotificationHelper {
if (DEBUG) Log.d(TAG, "Returning sender from group conversation notification.");
return person.getName();
}
+
+ /** Returns whether {@code entry} is suppressed from shade, meaning we should not show it. */
+ public static boolean shouldFilterOut(
+ Optional<Bubbles> bubblesOptional, NotificationEntry entry) {
+ return bubblesOptional.isPresent()
+ && bubblesOptional.get().isBubbleNotificationSuppressedFromShade(
+ entry.getKey(), entry.getSbn().getGroupKey());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 2602d7a3e369..39faf5a1eed9 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -26,6 +26,7 @@ import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE
import static com.android.systemui.people.NotificationHelper.getContactUri;
import static com.android.systemui.people.NotificationHelper.getHighestPriorityNotification;
+import static com.android.systemui.people.NotificationHelper.shouldFilterOut;
import static com.android.systemui.people.NotificationHelper.shouldMatchNotificationByUri;
import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING;
import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID;
@@ -87,6 +88,7 @@ import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
import java.util.Collections;
@@ -119,6 +121,7 @@ public class PeopleSpaceWidgetManager {
private NotificationEntryManager mNotificationEntryManager;
private PackageManager mPackageManager;
private INotificationManager mINotificationManager;
+ private Optional<Bubbles> mBubblesOptional;
private UserManager mUserManager;
private PeopleSpaceWidgetManager mManager;
public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
@@ -142,9 +145,9 @@ public class PeopleSpaceWidgetManager {
@Inject
public PeopleSpaceWidgetManager(Context context, LauncherApps launcherApps,
NotificationEntryManager notificationEntryManager,
- PackageManager packageManager, UserManager userManager,
- NotificationManager notificationManager, BroadcastDispatcher broadcastDispatcher,
- @Background Executor bgExecutor) {
+ PackageManager packageManager, Optional<Bubbles> bubblesOptional,
+ UserManager userManager, NotificationManager notificationManager,
+ BroadcastDispatcher broadcastDispatcher, @Background Executor bgExecutor) {
if (DEBUG) Log.d(TAG, "constructor");
mContext = context;
mAppWidgetManager = AppWidgetManager.getInstance(context);
@@ -157,6 +160,7 @@ public class PeopleSpaceWidgetManager {
mPackageManager = packageManager;
mINotificationManager = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ mBubblesOptional = bubblesOptional;
mUserManager = userManager;
mNotificationManager = notificationManager;
mManager = this;
@@ -207,8 +211,9 @@ public class PeopleSpaceWidgetManager {
AppWidgetManager appWidgetManager, IPeopleManager iPeopleManager,
PeopleManager peopleManager, LauncherApps launcherApps,
NotificationEntryManager notificationEntryManager, PackageManager packageManager,
- UserManager userManager, INotificationManager iNotificationManager,
- NotificationManager notificationManager, @Background Executor executor) {
+ Optional<Bubbles> bubblesOptional, UserManager userManager,
+ INotificationManager iNotificationManager, NotificationManager notificationManager,
+ @Background Executor executor) {
mContext = context;
mAppWidgetManager = appWidgetManager;
mIPeopleManager = iPeopleManager;
@@ -216,6 +221,7 @@ public class PeopleSpaceWidgetManager {
mLauncherApps = launcherApps;
mNotificationEntryManager = notificationEntryManager;
mPackageManager = packageManager;
+ mBubblesOptional = bubblesOptional;
mUserManager = userManager;
mINotificationManager = iNotificationManager;
mNotificationManager = notificationManager;
@@ -483,7 +489,8 @@ public class PeopleSpaceWidgetManager {
notifications
.stream()
.filter(entry -> NotificationHelper.isValid(entry)
- && NotificationHelper.isMissedCallOrHasContent(entry))
+ && NotificationHelper.isMissedCallOrHasContent(entry)
+ && !shouldFilterOut(mBubblesOptional, entry))
.collect(Collectors.groupingBy(
PeopleTileKey::new,
Collectors.mapping(Function.identity(), Collectors.toSet())));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 1c5fa439d0ee..e1a66b2c07ee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -615,10 +615,10 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
public void notifyCustomizeChanged() {
// The customize state changed, so our height changed.
mContainer.updateExpansion();
- mQSPanelScrollView.setVisibility(!mQSCustomizerController.isCustomizing() ? View.VISIBLE
- : View.INVISIBLE);
- mFooter.setVisibility(
- !mQSCustomizerController.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+ boolean customizing = isCustomizing();
+ mQSPanelScrollView.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
+ mFooter.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
+ mHeader.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
// Let the panel know the position changed and it needs to update where notifications
// and whatnot are.
mPanelView.onQsHeightChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index 64aec5e0b32b..7fab0f5f802c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -56,7 +56,6 @@ import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.systemui.wallet.ui.WalletActivity;
import java.util.List;
-import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -71,7 +70,6 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
private final KeyguardStateController mKeyguardStateController;
private final PackageManager mPackageManager;
private final SecureSettings mSecureSettings;
- private final Executor mExecutor;
private final QuickAccessWalletController mController;
private final FeatureFlags mFeatureFlags;
@@ -91,7 +89,6 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
KeyguardStateController keyguardStateController,
PackageManager packageManager,
SecureSettings secureSettings,
- @Main Executor executor,
QuickAccessWalletController quickAccessWalletController,
FeatureFlags featureFlags) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
@@ -100,7 +97,6 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
mKeyguardStateController = keyguardStateController;
mPackageManager = packageManager;
mSecureSettings = secureSettings;
- mExecutor = executor;
mFeatureFlags = featureFlags;
}
@@ -118,6 +114,7 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
if (listening) {
mController.setupWalletChangeObservers(mCardRetriever, DEFAULT_PAYMENT_APP_CHANGE);
if (!mController.getWalletClient().isWalletServiceAvailable()) {
+ Log.i(TAG, "QAW service is unavailable, recreating the wallet client.");
mController.reCreateWalletClient();
}
mController.queryWalletCards(mCardRetriever);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 0df69a0a1f43..9fa460928e13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -204,6 +204,12 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
return;
}
NotificationEntry entry = alertEntry.mEntry;
+
+ // If the notification is animating, we will remove it at the end of the animation.
+ if (entry != null && entry.isExpandAnimationRunning()) {
+ return;
+ }
+
mAlertEntries.remove(key);
onAlertEntryRemoved(alertEntry);
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index 071e9472a41b..ce796d9789cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -107,6 +107,8 @@ open class BlurUtils @Inject constructor(
it.println("minBlurRadius: $minBlurRadius")
it.println("maxBlurRadius: $maxBlurRadius")
it.println("supportsBlursOnWindows: ${supportsBlursOnWindows()}")
+ it.println("CROSS_WINDOW_BLUR_SUPPORTED: $CROSS_WINDOW_BLUR_SUPPORTED")
+ it.println("isHighEndGfx: ${ActivityManager.isHighEndGfx()}")
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index e11e67dfaf1b..f7b3a350ddf4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -20,14 +20,11 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
-import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.MathUtils;
-import android.view.DisplayCutout;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
-import android.view.WindowInsets;
import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -666,8 +663,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf();
iconState.hidden = isAppearing
|| (view instanceof ExpandableNotificationRow
- && ((ExpandableNotificationRow) view).isLowPriority()
- && mShelfIcons.hasMaxNumDot())
+ && ((ExpandableNotificationRow) view).isLowPriority()
+ && mShelfIcons.hasMaxNumDot())
|| (transitionAmount == 0.0f && !iconState.isAnimating(icon))
|| row.isAboveShelf()
|| row.showingPulsing()
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 bce39ce80d35..c248670c48db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -7,6 +7,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController
+import com.android.systemui.statusbar.policy.HeadsUpUtil
import kotlin.math.ceil
import kotlin.math.max
@@ -22,8 +23,8 @@ class NotificationLaunchAnimatorControllerProvider(
return NotificationLaunchAnimatorController(
notificationShadeWindowViewController,
notificationListContainer,
- notification,
- headsUpManager
+ headsUpManager,
+ notification
)
}
}
@@ -36,10 +37,11 @@ class NotificationLaunchAnimatorControllerProvider(
class NotificationLaunchAnimatorController(
private val notificationShadeWindowViewController: NotificationShadeWindowViewController,
private val notificationListContainer: NotificationListContainer,
- private val notification: ExpandableNotificationRow,
- private val headsUpManager: HeadsUpManagerPhone
+ private val headsUpManager: HeadsUpManagerPhone,
+ private val notification: ExpandableNotificationRow
) : ActivityLaunchAnimator.Controller {
- private val notificationKey = notification.entry.sbn.key
+ private val notificationEntry = notification.entry
+ private val notificationKey = notificationEntry.sbn.key
override var launchContainer: ViewGroup
get() = notification.rootView as ViewGroup
@@ -82,6 +84,7 @@ class NotificationLaunchAnimatorController(
override fun onIntentStarted(willAnimate: Boolean) {
notificationShadeWindowViewController.setExpandAnimationRunning(willAnimate)
+ notificationEntry.isExpandAnimationRunning = willAnimate
if (!willAnimate) {
removeHun(animate = true)
@@ -93,6 +96,7 @@ class NotificationLaunchAnimatorController(
return
}
+ HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(notification, animate)
headsUpManager.removeNotification(notificationKey, true /* releaseImmediately */, animate)
}
@@ -100,6 +104,7 @@ class NotificationLaunchAnimatorController(
// TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started
// here?
notificationShadeWindowViewController.setExpandAnimationRunning(false)
+ notificationEntry.isExpandAnimationRunning = false
removeHun(animate = true)
}
@@ -116,6 +121,7 @@ class NotificationLaunchAnimatorController(
notification.isExpandAnimationRunning = false
notificationShadeWindowViewController.setExpandAnimationRunning(false)
+ notificationEntry.isExpandAnimationRunning = false
notificationListContainer.setExpandingNotification(null)
applyParams(null)
removeHun(animate = false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 5f93f4807c73..9f82152eb5ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -179,6 +179,7 @@ public final class NotificationEntry extends ListEntry {
private boolean mIsAlerting;
public boolean mRemoteEditImeVisible;
+ private boolean mExpandAnimationRunning;
/**
* @param sbn the StatusBarNotification from system server
@@ -952,6 +953,16 @@ public final class NotificationEntry extends ListEntry {
return mIsAlerting;
}
+ /** Set whether this notification is currently used to animate a launch. */
+ public void setExpandAnimationRunning(boolean expandAnimationRunning) {
+ mExpandAnimationRunning = expandAnimationRunning;
+ }
+
+ /** Whether this notification is currently used to animate a launch. */
+ public boolean isExpandAnimationRunning() {
+ return mExpandAnimationRunning;
+ }
+
/** Information about a suggestion that is being edited. */
public static class EditedSuggestionInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 61f6ad54bc26..b18f191c4333 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.row;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
@@ -84,7 +83,16 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
* or {@link #setOverrideTintColor(int, float)}.
*/
protected static final int NO_COLOR = 0;
-
+ /**
+ * The content of the view should start showing at animation progress value of
+ * #ALPHA_APPEAR_START_FRACTION.
+ */
+ private static final float ALPHA_APPEAR_START_FRACTION = .4f;
+ /**
+ * The content should show fully with progress at #ALPHA_APPEAR_END_FRACTION
+ * The start of the animation is at #ALPHA_APPEAR_START_FRACTION
+ */
+ private static final float ALPHA_APPEAR_END_FRACTION = 1;
private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
= new PathInterpolator(0.6f, 0, 0.5f, 1);
private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
@@ -106,10 +114,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private final Interpolator mSlowOutFastInInterpolator;
private final Interpolator mSlowOutLinearInInterpolator;
private Interpolator mCurrentAppearInterpolator;
- private Interpolator mCurrentAlphaInterpolator;
NotificationBackgroundView mBackgroundNormal;
- private ObjectAnimator mBackgroundAnimator;
private RectF mAppearAnimationRect = new RectF();
private float mAnimationTranslationY;
private boolean mDrawingAppearAnimation;
@@ -475,8 +481,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
long duration, final Runnable onFinishedRunnable,
AnimatorListenerAdapter animationListener) {
- cancelAppearAnimation();
mAnimationTranslationY = translationDirection * getActualHeight();
+ cancelAppearAnimation();
if (mAppearAnimationFraction == -1.0f) {
// not initialized yet, we start anew
if (isAppearing) {
@@ -492,15 +498,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
float targetValue;
if (isAppearing) {
mCurrentAppearInterpolator = mSlowOutFastInInterpolator;
- mCurrentAlphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
targetValue = 1.0f;
- if (!mIsHeadsUpAnimation && isChildInGroup()) {
- // slower fade in of children to avoid visibly overlapping with other children
- mCurrentAlphaInterpolator = Interpolators.SLOW_OUT_LINEAR_IN;
- }
} else {
mCurrentAppearInterpolator = Interpolators.FAST_OUT_SLOW_IN;
- mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator;
targetValue = 0.0f;
}
mAppearAnimator = ValueAnimator.ofFloat(mAppearAnimationFraction,
@@ -588,61 +588,23 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
float translationFraction = mCurrentAppearInterpolator.getInterpolation(inverseFraction);
float translateYTotalAmount = translationFraction * mAnimationTranslationY;
mAppearAnimationTranslation = translateYTotalAmount;
+ final int actualHeight = getActualHeight();
+ float bottom = actualHeight * mAppearAnimationFraction;
- // handle width animation
- float widthFraction = (inverseFraction - (1.0f - HORIZONTAL_ANIMATION_START))
- / (HORIZONTAL_ANIMATION_START - HORIZONTAL_ANIMATION_END);
- widthFraction = Math.min(1.0f, Math.max(0.0f, widthFraction));
- widthFraction = mCurrentAppearInterpolator.getInterpolation(widthFraction);
- float startWidthFraction = HORIZONTAL_COLLAPSED_REST_PARTIAL;
- if (mIsHeadsUpAnimation && !mIsAppearing) {
- startWidthFraction = 0;
- }
- if (mIsAppearing && !mIsHeadsUpAnimation && isChildInGroup()) {
- // Children in a group (when not heads up) should simply fade in.
- startWidthFraction = 1;
- }
- float width = MathUtils.lerp(startWidthFraction, 1.0f, 1.0f - widthFraction)
- * getWidth();
- float left;
- float right;
- if (mIsHeadsUpAnimation) {
- left = MathUtils.lerp(mHeadsUpLocation, 0, 1.0f - widthFraction);
- right = left + width;
- } else {
- left = getWidth() * 0.5f - width / 2.0f;
- right = getWidth() - left;
- }
-
- // handle top animation
- float heightFraction = (inverseFraction - (1.0f - VERTICAL_ANIMATION_START)) /
- VERTICAL_ANIMATION_START;
- heightFraction = Math.max(0.0f, heightFraction);
- heightFraction = mCurrentAppearInterpolator.getInterpolation(heightFraction);
+ setOutlineRect(0, mAppearAnimationTranslation,
+ getWidth(), bottom + mAppearAnimationTranslation);
+ }
- float top;
- float bottom;
- final int actualHeight = getActualHeight();
- if (mAnimationTranslationY > 0.0f) {
- bottom = actualHeight - heightFraction * mAnimationTranslationY * 0.1f
- - translateYTotalAmount;
- top = bottom * heightFraction;
- } else {
- top = heightFraction * (actualHeight + mAnimationTranslationY) * 0.1f -
- translateYTotalAmount;
- bottom = actualHeight * (1 - heightFraction) + top * heightFraction;
- }
- mAppearAnimationRect.set(left, top, right, bottom);
- setOutlineRect(left, top + mAppearAnimationTranslation, right,
- bottom + mAppearAnimationTranslation);
+ private float getAppearAnimationFraction() {
+ return mAppearAnimationFraction >= 0 ? mAppearAnimationFraction : 1;
}
private void updateAppearAnimationAlpha() {
- float contentAlphaProgress = mAppearAnimationFraction;
- contentAlphaProgress = contentAlphaProgress / (1.0f - ALPHA_ANIMATION_END);
- contentAlphaProgress = Math.min(1.0f, contentAlphaProgress);
- contentAlphaProgress = mCurrentAlphaInterpolator.getInterpolation(contentAlphaProgress);
- setContentAlpha(contentAlphaProgress);
+ float contentAlphaProgress = MathUtils.constrain(mAppearAnimationFraction,
+ ALPHA_APPEAR_START_FRACTION, ALPHA_APPEAR_END_FRACTION);
+ float range = ALPHA_APPEAR_END_FRACTION - ALPHA_APPEAR_START_FRACTION;
+ float alpha = (contentAlphaProgress - ALPHA_APPEAR_START_FRACTION) / range;
+ setContentAlpha(Interpolators.ALPHA_IN.getInterpolation(alpha));
}
private void setContentAlpha(float contentAlpha) {
@@ -665,6 +627,22 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
getCurrentBackgroundRadiusBottom());
}
+ @Override
+ public float getCurrentBackgroundRadiusTop() {
+ float fraction = getAppearAnimationFraction();
+ return isHeadsUpAnimatingAway() || isHeadsUp()
+ ? mOutlineRadius * fraction
+ : super.getCurrentBackgroundRadiusTop();
+ }
+
+ @Override
+ public float getCurrentBackgroundRadiusBottom() {
+ float fraction = getAppearAnimationFraction();
+ return isHeadsUpAnimatingAway() || isHeadsUp()
+ ? mOutlineRadius * fraction
+ : super.getCurrentBackgroundRadiusBottom();
+ }
+
private void applyBackgroundRoundness(float topRadius, float bottomRadius) {
mBackgroundNormal.setRadius(topRadius, bottomRadius);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index d68271a19d04..6fd556763943 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1997,23 +1997,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return false;
}
- @Override
- public float getCurrentTopRoundness() {
- if (mExpandAnimationRunning) {
- return mTopRoundnessDuringExpandAnimation;
- }
-
- return super.getCurrentTopRoundness();
- }
-
- @Override
- public float getCurrentBottomRoundness() {
- if (mExpandAnimationRunning) {
- return mBottomRoundnessDuringExpandAnimation;
- }
-
- return super.getCurrentBottomRoundness();
- }
public void applyExpandAnimationParams(ExpandAnimationParameters params) {
if (params == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index a18917789ba1..0c86262d9037 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -83,7 +83,7 @@ public class AmbientState {
private ExpandableNotificationRow mTrackedHeadsUpRow;
private float mAppearFraction;
private boolean mIsShadeOpening;
- private float mSectionPadding;
+ private float mOverExpansion;
/** Distance of top of notifications panel from top of screen. */
private float mStackY = 0;
@@ -182,12 +182,12 @@ public class AmbientState {
return mIsShadeOpening;
}
- void setSectionPadding(float padding) {
- mSectionPadding = padding;
+ void setOverExpansion(float overExpansion) {
+ mOverExpansion = overExpansion;
}
- float getSectionPadding() {
- return mSectionPadding;
+ float getOverExpansion() {
+ return mOverExpansion;
}
private static int getZDistanceBetweenElements(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java
index 6cd229037462..5343cbf4f9fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java
@@ -117,16 +117,6 @@ public class AnimationFilter {
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_GO_TO_FULL_SHADE) {
hasGoToFullShadeEvent = true;
}
- if (ev.animationType == NotificationStackScrollLayout.AnimationEvent
- .ANIMATION_TYPE_HEADS_UP_DISAPPEAR) {
- customDelay = StackStateAnimator.ANIMATION_DELAY_HEADS_UP;
- } else if (ev.animationType == NotificationStackScrollLayout.AnimationEvent
- .ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
- // We need both timeouts when clicking, one to delay it and one for the animation
- // to look nice
- customDelay = StackStateAnimator.ANIMATION_DELAY_HEADS_UP_CLICKED
- + StackStateAnimator.ANIMATION_DELAY_HEADS_UP;
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 64f228f41df9..9390c81a847b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -119,6 +119,7 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
@@ -470,6 +471,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
};
+ private Consumer<Integer> mScrollListener;
private final ScrollAdapter mScrollAdapter = new ScrollAdapter() {
@Override
public boolean isScrolledToTop() {
@@ -552,8 +554,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
- void setSectionPadding(float margin) {
- mAmbientState.setSectionPadding(margin);
+ /**
+ * Set the overexpansion of the panel to be applied to the view.
+ */
+ void setOverExpansion(float margin) {
+ mAmbientState.setOverExpansion(margin);
+ updateStackPosition();
requestChildrenUpdate();
}
@@ -1136,7 +1142,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
private void updateStackPosition() {
// Consider interpolating from an mExpansionStartY for use on lockscreen and AOD
- float endTopPosition = mTopPadding + mExtraTopInsetForFullShadeTransition;
+ float endTopPosition = mTopPadding + mExtraTopInsetForFullShadeTransition
+ + mAmbientState.getOverExpansion();
final float fraction = mAmbientState.getExpansionFraction();
final float stackY = MathUtils.lerp(0, endTopPosition, fraction);
mAmbientState.setStackY(stackY);
@@ -1144,7 +1151,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mOnStackYChanged.run();
}
if (mQsExpansionFraction <= 0) {
- final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mSidePaddings;
final float stackEndHeight = Math.max(0f,
getHeight() - getEmptyBottomMargin() - mTopPadding);
mAmbientState.setStackEndHeight(stackEndHeight);
@@ -1166,7 +1172,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setExpandedHeight(float height) {
final float shadeBottom = getHeight() - getEmptyBottomMargin();
- final float expansionFraction = MathUtils.constrain(height / shadeBottom, 0f, 1f);
+ final float expansionFraction = MathUtils.saturate(height / shadeBottom);
mAmbientState.setExpansionFraction(expansionFraction);
updateStackPosition();
@@ -2395,8 +2401,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
float topOverScroll = getCurrentOverScrollAmount(true);
return mScrolledToTopOnFirstDown
&& !mExpandedInThisMotion
- && topOverScroll > mMinTopOverScrollToEscape
- && initialVelocity > 0;
+ && (initialVelocity > mMinimumVelocity
+ || (topOverScroll > mMinTopOverScrollToEscape && initialVelocity > 0));
}
/**
@@ -4552,6 +4558,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
private void updateOnScrollChange() {
+ if (mScrollListener != null) {
+ mScrollListener.accept(mOwnScrollY);
+ }
updateForwardAndBackwardScrollability();
requestChildrenUpdate();
}
@@ -5163,6 +5172,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
/**
+ * Set a listener to when scrolling changes.
+ */
+ public void setOnScrollListener(Consumer<Integer> listener) {
+ mScrollListener = listener;
+ }
+
+ /**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
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 4432f5463802..a6bba93d9816 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
@@ -124,6 +124,7 @@ import com.android.systemui.tuner.TunerService;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
@@ -302,8 +303,11 @@ public class NotificationStackScrollLayoutController {
}
};
- public void setSectionPadding(float padding) {
- mView.setSectionPadding(padding);
+ /**
+ * Set the overexpansion of the panel to be applied to the view.
+ */
+ public void setOverExpansion(float overExpansion) {
+ mView.setOverExpansion(overExpansion);
}
private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
@@ -944,10 +948,6 @@ public class NotificationStackScrollLayoutController {
mView.setOverScrollAmount(amount, onTop, animate);
}
- public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
- mView.setOverScrolledPixels(numPixels, onTop, animate);
- }
-
public void resetScrollPosition() {
mView.resetScrollPosition();
}
@@ -1054,10 +1054,6 @@ public class NotificationStackScrollLayoutController {
return mView.getCurrentOverScrollAmount(top);
}
- public float getCurrentOverScrolledPixels(boolean top) {
- return mView.getCurrentOverScrolledPixels(top);
- }
-
public float calculateAppearFraction(float height) {
return mView.calculateAppearFraction(height);
}
@@ -1431,6 +1427,13 @@ public class NotificationStackScrollLayoutController {
}
/**
+ * Set a listener to when scrolling changes.
+ */
+ public void setOnScrollListener(Consumer<Integer> listener) {
+ mView.setOnScrollListener(listener);
+ }
+
+ /**
* Enum for UiEvent logged from this class
*/
enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 5f9c1d769c3a..a02ebbfa3521 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -403,10 +403,6 @@ public class StackScrollAlgorithm {
}
viewState.yTranslation = algorithmState.mCurrentYPosition;
- if (view instanceof SectionHeaderView) {
- // Add padding before sections for overscroll effect.
- viewState.yTranslation += expansionFraction * ambientState.getSectionPadding();
- }
if (view instanceof FooterView) {
final boolean shadeClosed = !ambientState.isShadeExpanded();
@@ -538,7 +534,7 @@ public class StackScrollAlgorithm {
continue;
}
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- if (!row.isHeadsUp()) {
+ if (!(row.isHeadsUp() || row.isHeadsUpAnimatingAway())) {
continue;
}
ExpandableViewState childState = row.getViewState();
@@ -585,6 +581,7 @@ public class StackScrollAlgorithm {
}
}
if (row.isHeadsUpAnimatingAway()) {
+ childState.yTranslation = Math.max(childState.yTranslation, mHeadsUpInset);
childState.hidden = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 883f9f26c518..83dc6df5415a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -63,8 +63,6 @@ public class StackStateAnimator {
public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32;
public static final int ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE = 48;
public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
- public static final int ANIMATION_DELAY_HEADS_UP = 120;
- public static final int ANIMATION_DELAY_HEADS_UP_CLICKED= 120;
private static final int MAX_STAGGER_COUNT = 5;
private static final HeadsUpAppearInterpolator HEADS_UP_APPEAR_INTERPOLATOR =
new HeadsUpAppearInterpolator();
@@ -424,7 +422,6 @@ public class StackStateAnimator {
if (event.headsUpFromBottom) {
mTmpState.yTranslation = mHeadsUpAppearHeightBottom;
} else {
- mTmpState.yTranslation = 0;
changingView.performAddAnimation(0, ANIMATION_DURATION_HEADS_UP_APPEAR_CLOSED,
true /* isHeadsUpAppear */);
}
@@ -436,24 +433,11 @@ public class StackStateAnimator {
.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
mHeadsUpDisappearChildren.add(changingView);
Runnable endRunnable = null;
- // We need some additional delay in case we were removed to make sure we're not
- // lagging
- int extraDelay = event.animationType == NotificationStackScrollLayout
- .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
- ? ANIMATION_DELAY_HEADS_UP_CLICKED
- : 0;
if (changingView.getParent() == null) {
// This notification was actually removed, so we need to add it transiently
mHostLayout.addTransientView(changingView, 0);
changingView.setTransientContainer(mHostLayout);
mTmpState.initFrom(changingView);
- mTmpState.yTranslation = 0;
- // We temporarily enable Y animations, the real filter will be combined
- // afterwards anyway
- mAnimationFilter.animateY = true;
- mAnimationProperties.delay = extraDelay + ANIMATION_DELAY_HEADS_UP;
- mAnimationProperties.duration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR;
- mTmpState.animateTo(changingView, mAnimationProperties);
endRunnable = () -> removeTransientView(changingView);
}
float targetLocation = 0;
@@ -483,8 +467,8 @@ public class StackStateAnimator {
// running anymore, the panel will instantly hide itself. We need to wait until
// the animation is fully finished for this though.
long removeAnimationDelay = changingView.performRemoveAnimation(
- ANIMATION_DURATION_HEADS_UP_DISAPPEAR + ANIMATION_DELAY_HEADS_UP,
- extraDelay, 0.0f, true /* isHeadsUpAppear */, targetLocation,
+ ANIMATION_DURATION_HEADS_UP_DISAPPEAR,
+ 0, 0.0f, true /* isHeadsUpAppear */, targetLocation,
endRunnable, getGlobalAnimationFinishedListener());
mAnimationProperties.delay += removeAnimationDelay;
} else if (endRunnable != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index df86e2012564..6d82a45313d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -591,7 +591,7 @@ public class ViewState implements Dumpable {
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- HeadsUpUtil.setIsClickedHeadsUpNotification(child, false);
+ HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(child, false);
child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
child.setTag(TAG_START_TRANSLATION_Y, null);
child.setTag(TAG_END_TRANSLATION_Y, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 4d8e7de37606..8e3aed43d1af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -368,8 +368,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
updateLeftAffordanceIcon();
lp = mWalletButton.getLayoutParams();
- lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
- lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
+ lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width);
+ lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width);
mWalletButton.setLayoutParams(lp);
mIndicationPadding = getResources().getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 3a01791380ed..32b3e51076d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -510,7 +510,6 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mShowingKeyguardHeadsUp;
private boolean mAllowExpandForSmallExpansion;
private Runnable mExpandAfterLayoutRunnable;
- private float mSectionPadding;
/**
* The padding between the start of notifications and the qs boundary on the lockscreen.
@@ -589,7 +588,6 @@ public class NotificationPanelViewController extends PanelViewController {
private NotificationShelfController mNotificationShelfController;
private int mScrimCornerRadius;
private int mScreenCornerRadius;
- private int mNotificationScrimPadding;
private boolean mQSAnimatingHiddenFromCollapsed;
private final Executor mUiExecutor;
@@ -824,6 +822,7 @@ public class NotificationPanelViewController extends PanelViewController {
mOnHeightChangedListener);
mNotificationStackScrollLayoutController.setOverscrollTopChangedListener(
mOnOverscrollTopChangedListener);
+ mNotificationStackScrollLayoutController.setOnScrollListener(this::onNotificationScrolled);
mNotificationStackScrollLayoutController.setOnEmptySpaceClickListener(
mOnEmptySpaceClickListener);
addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp);
@@ -908,8 +907,6 @@ public class NotificationPanelViewController extends PanelViewController {
mScrimCornerRadius = mResources.getDimensionPixelSize(
R.dimen.notification_scrim_corner_radius);
mScreenCornerRadius = (int) ScreenDecorationsUtils.getWindowCornerRadius(mResources);
- mNotificationScrimPadding = mResources.getDimensionPixelSize(
- R.dimen.notification_side_paddings);
mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
R.dimen.notification_side_paddings);
}
@@ -2190,6 +2187,22 @@ public class NotificationPanelViewController extends PanelViewController {
}
};
+ private void onNotificationScrolled(int newScrollPosition) {
+ // Since this is an overscroller, sometimes the scrollY can be temporarily negative
+ // (when overscrollng on the top and flinging). Let's
+ updateQSExpansionEnabled();
+ }
+
+ @Override
+ public void setIsShadeOpening(boolean opening) {
+ mAmbientState.setIsShadeOpening(opening);
+ updateQSExpansionEnabled();
+ }
+
+ private void updateQSExpansionEnabled() {
+ setQsExpansionEnabled(mAmbientState.getScrollY() <= 0 && !mAmbientState.isShadeOpening());
+ }
+
/**
* Updates scrim bounds, QS clipping, and KSV clipping as well based on the bounds of the shade
* and QS state.
@@ -2203,7 +2216,6 @@ public class NotificationPanelViewController extends PanelViewController {
final int qsPanelBottomY = calculateQsBottomPosition(computeQsExpansionFraction());
final boolean visible = (computeQsExpansionFraction() > 0 || qsPanelBottomY > 0)
&& !mShouldUseSplitNotificationShade;
- setQsExpansionEnabled(mAmbientState.getScrollY() == 0 && !mAmbientState.isShadeOpening());
if (!mShouldUseSplitNotificationShade) {
if (mTransitioningToFullShadeProgress > 0.0f) {
@@ -2221,11 +2233,14 @@ public class NotificationPanelViewController extends PanelViewController {
left = 0;
right = getView().getRight() + mDisplayRightInset;
} else if (qsPanelBottomY > 0) { // so bounds are empty on lockscreen
+ mAmbientState.setNotificationScrimTop(mSplitShadeNotificationsTopPadding);
top = Math.min(qsPanelBottomY, mSplitShadeNotificationsTopPadding);
bottom = mNotificationStackScrollLayoutController.getHeight();
left = mNotificationStackScrollLayoutController.getLeft();
right = mNotificationStackScrollLayoutController.getRight();
}
+ // top should never be lower than bottom, otherwise it will be invisible.
+ top = Math.min(top, bottom);
applyQSClippingBounds(left, top, right, bottom, visible);
}
@@ -2313,8 +2328,6 @@ public class NotificationPanelViewController extends PanelViewController {
qsBottomY = (int) MathUtils.lerp(
qsBottomY, mQs.getDesiredHeight(), qsExpansionFraction);
}
- // to account for shade overshooting animation, see setSectionPadding method
- if (mSectionPadding > 0) qsBottomY += mSectionPadding;
return qsBottomY;
}
}
@@ -2630,7 +2643,7 @@ public class NotificationPanelViewController extends PanelViewController {
int min = mStatusBarMinHeight;
if (!(mBarState == KEYGUARD)
&& mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) {
- int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
+ int minHeight = mQsMinExpansionHeight;
min = Math.max(min, minHeight);
}
int maxHeight;
@@ -2642,8 +2655,8 @@ public class NotificationPanelViewController extends PanelViewController {
}
maxHeight = Math.max(min, maxHeight);
if (maxHeight == 0 || isNaN(maxHeight)) {
- Log.wtf(TAG, "maxPanelHeight is invalid. getOverExpansionAmount(): "
- + getOverExpansionAmount() + ", calculatePanelHeightQsExpanded: "
+ Log.wtf(TAG, "maxPanelHeight is invalid. mOverExpansion: "
+ + mOverExpansion + ", calculatePanelHeightQsExpanded: "
+ calculatePanelHeightQsExpanded() + ", calculatePanelHeightShade: "
+ calculatePanelHeightShade() + ", mStatusBarMinHeight = "
+ mStatusBarMinHeight + ", mQsMinExpansionHeight = " + mQsMinExpansionHeight);
@@ -2805,23 +2818,6 @@ public class NotificationPanelViewController extends PanelViewController {
return alpha;
}
- @Override
- protected float getOverExpansionAmount() {
- float result = mNotificationStackScrollLayoutController
- .getCurrentOverScrollAmount(true /* top */);
- if (isNaN(result)) {
- Log.wtf(TAG, "OverExpansionAmount is NaN!");
- }
-
- return result;
- }
-
- @Override
- protected float getOverExpansionPixels() {
- return mNotificationStackScrollLayoutController
- .getCurrentOverScrolledPixels(true /* top */);
- }
-
/**
* Hides the header when notifications are colliding with it.
*/
@@ -3016,31 +3012,15 @@ public class NotificationPanelViewController extends PanelViewController {
}
@Override
- public void setSectionPadding(float padding) {
- if (padding == mSectionPadding) {
+ public void setOverExpansion(float overExpansion) {
+ if (overExpansion == mOverExpansion) {
return;
}
- mSectionPadding = padding;
- // TODO(b/172289889) update overscroll to spec
- }
-
- @Override
- protected void setOverExpansion(float overExpansion, boolean isPixels) {
- if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
- return;
- }
- if (mBarState != KEYGUARD) {
- mNotificationStackScrollLayoutController.setOnHeightChangedListener(null);
- if (isPixels) {
- mNotificationStackScrollLayoutController.setOverScrolledPixels(
- overExpansion, true /* onTop */, false /* animate */);
- } else {
- mNotificationStackScrollLayoutController.setOverScrollAmount(
- overExpansion, true /* onTop */, false /* animate */);
- }
- mNotificationStackScrollLayoutController
- .setOnHeightChangedListener(mOnHeightChangedListener);
- }
+ super.setOverExpansion(overExpansion);
+ // Translating the quick settings by half the overexpansion to center it in the background
+ // frame
+ mQsFrame.setTranslationY(overExpansion / 2f);
+ mNotificationStackScrollLayoutController.setOverExpansion(overExpansion);
}
@Override
@@ -3064,7 +3044,7 @@ public class NotificationPanelViewController extends PanelViewController {
mFalsingCollector.onTrackingStopped();
super.onTrackingStopped(expand);
if (expand) {
- mNotificationStackScrollLayoutController.setOverScrolledPixels(0.0f, true /* onTop */,
+ mNotificationStackScrollLayoutController.setOverScrollAmount(0.0f, true /* onTop */,
true /* animate */);
}
mNotificationStackScrollLayoutController.onPanelTrackingStopped();
@@ -3110,18 +3090,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
@Override
- protected boolean fullyExpandedClearAllVisible() {
- return mNotificationStackScrollLayoutController.isFooterViewNotGone()
- && mNotificationStackScrollLayoutController.isScrolledToBottom()
- && !mQsExpandImmediate;
- }
-
- @Override
- protected boolean isClearAllVisible() {
- return mNotificationStackScrollLayoutController.isFooterViewContentVisible();
- }
-
- @Override
protected boolean isTrackingBlocked() {
return mConflictingQsExpansionGesture && mQsExpanded || mBlockingExpansionForCurrentTouch;
}
@@ -3971,10 +3939,15 @@ public class NotificationPanelViewController extends PanelViewController {
}
mLastOverscroll = 0f;
mQsExpansionFromOverscroll = false;
+ if (open) {
+ // During overscrolling, qsExpansion doesn't actually change that the qs is
+ // becoming expanded. Any layout could therefore reset the position again. Let's
+ // make sure we can expand
+ setOverScrolling(false);
+ }
setQsExpansion(mQsExpansionHeight);
flingSettings(!mQsExpansionEnabled && open ? 0f : velocity,
open && mQsExpansionEnabled ? FLING_EXPAND : FLING_COLLAPSE, () -> {
- mStackScrollerOverscrolling = false;
setOverScrolling(false);
updateQsState();
}, false /* isClick */);
@@ -4390,7 +4363,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (mQsMaxExpansionHeight != oldMaxHeight) {
startQsSizeChangeAnimation(oldMaxHeight, mQsMaxExpansionHeight);
}
- } else if (!mQsExpanded) {
+ } else if (!mQsExpanded && mQsExpansionAnimator == null) {
setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
}
updateExpandedHeight(getExpandedHeight());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 64e2c1c5d268..f1b6c7c3ad19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -53,7 +53,7 @@ public abstract class PanelBar extends FrameLayout {
if (DEBUG) LOG("go state: %d -> %d", mState, state);
mState = state;
if (mPanel != null) {
- mPanel.getAmbientState().setIsShadeOpening(state == STATE_OPENING);
+ mPanel.setIsShadeOpening(state == STATE_OPENING);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 798e8953b170..323a1128d3bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -68,12 +68,14 @@ public abstract class PanelViewController {
public static final String TAG = PanelView.class.getSimpleName();
private static final int NO_FIXED_DURATION = -1;
private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L;
- private static final long SHADE_OPEN_SPRING_BACK_DURATION = 200L;
- private static final float MIN_OVERSCROLL = -50;
- private static final float MAX_OVERSCROLL = 30;
+ private static final long SHADE_OPEN_SPRING_BACK_DURATION = 400L;
+
+ /**
+ * The factor of the usual high velocity that is needed in order to reach the maximum overshoot
+ * when flinging. A low value will make it that most flings will reach the maximum overshoot.
+ */
+ private static final float FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT = 0.5f;
- private float mFlingTarget;
- private float mFlingVelocity;
protected long mDownTime;
protected boolean mTouchSlopExceededBeforeDown;
private float mMinExpandHeight;
@@ -83,6 +85,22 @@ public abstract class PanelViewController {
protected boolean mIsLaunchAnimationRunning;
private int mFixedDuration = NO_FIXED_DURATION;
protected ArrayList<PanelExpansionListener> mExpansionListeners = new ArrayList<>();
+ protected float mOverExpansion;
+
+ /**
+ * The overshoot amount when the panel flings open
+ */
+ private float mPanelFlingOvershootAmount;
+
+ /**
+ * The amount of pixels that we have overexpanded the last time with a gesture
+ */
+ private float mLastGesturedOverExpansion = -1;
+
+ /**
+ * Is the current animator the spring back animation?
+ */
+ private boolean mIsSpringBackAnimation;
private void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -254,6 +272,7 @@ public abstract class PanelViewController {
mTouchSlop = configuration.getScaledTouchSlop();
mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
mHintDistance = mResources.getDimension(R.dimen.hint_move_distance);
+ mPanelFlingOvershootAmount = mResources.getDimension(R.dimen.panel_overshoot_amount);
mUnlockFalsingThreshold = mResources.getDimensionPixelSize(
R.dimen.unlock_falsing_threshold);
}
@@ -529,21 +548,38 @@ public abstract class PanelViewController {
protected void flingToHeight(float vel, boolean expand, float target,
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
- if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
+ if (target == mExpandedHeight && mOverExpansion == 0.0f) {
+ // We're at the target and didn't fling and there's no overshoot
endJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
mKeyguardStateController.notifyPanelFlingEnd();
notifyExpandingFinished();
return;
}
mIsFlinging = true;
- mOverExpandedBeforeFling = getOverExpansionAmount() > 0f;
- ValueAnimator animator = createHeightAnimator(target);
- mFlingTarget = target;
+ // we want to perform an overshoot animation when flinging open
+ final boolean addOverscroll = expand
+ && mStatusBarStateController.getState() != StatusBarState.KEYGUARD
+ && mOverExpansion == 0.0f
+ && vel >= 0;
+ final boolean shouldSpringBack = addOverscroll || (mOverExpansion != 0.0f && expand);
+ float overshootAmount = 0.0f;
+ if (addOverscroll) {
+ // Let's overshoot depending on the amount of velocity
+ overshootAmount = MathUtils.lerp(
+ 0.2f,
+ 1.0f,
+ MathUtils.saturate(vel
+ / (mFlingAnimationUtils.getHighVelocityPxPerSecond()
+ * FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT)));
+ overshootAmount += mOverExpansion / mPanelFlingOvershootAmount;
+ }
+ ValueAnimator animator = createHeightAnimator(target, overshootAmount);
if (expand) {
if (expandBecauseOfFalsing && vel < 0) {
vel = 0;
}
- mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, mView.getHeight());
+ mFlingAnimationUtils.apply(animator, mExpandedHeight,
+ target + overshootAmount * mPanelFlingOvershootAmount, vel, mView.getHeight());
if (vel == 0) {
animator.setDuration(SHADE_OPEN_SPRING_OUT_DURATION);
}
@@ -570,7 +606,6 @@ public abstract class PanelViewController {
animator.setDuration(mFixedDuration);
}
}
- mFlingVelocity = vel;
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -586,7 +621,7 @@ public abstract class PanelViewController {
@Override
public void onAnimationEnd(Animator animation) {
- if (expand && mFlingVelocity > 0) {
+ if (shouldSpringBack && !mCancelled) {
// After the shade is flinged open to an overscrolled state, spring back
// the shade by reducing section padding to 0.
springBack();
@@ -600,14 +635,19 @@ public abstract class PanelViewController {
}
private void springBack() {
- ValueAnimator animator = ValueAnimator.ofFloat(MAX_OVERSCROLL, 0);
+ if (mOverExpansion == 0) {
+ onFlingEnd(false /* cancelled */);
+ return;
+ }
+ mIsSpringBackAnimation = true;
+ ValueAnimator animator = ValueAnimator.ofFloat(mOverExpansion, 0);
animator.addUpdateListener(
animation -> {
- setSectionPadding((float) animation.getAnimatedValue());
- setExpandedHeightInternal(mFlingTarget);
+ setOverExpansionInternal((float) animation.getAnimatedValue(),
+ false /* isFromGesture */);
});
animator.setDuration(SHADE_OPEN_SPRING_BACK_DURATION);
- animator.setInterpolator(Interpolators.LINEAR);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@Override
@@ -616,6 +656,7 @@ public abstract class PanelViewController {
}
@Override
public void onAnimationEnd(Animator animation) {
+ mIsSpringBackAnimation = false;
onFlingEnd(mCancelled);
}
});
@@ -625,6 +666,8 @@ public abstract class PanelViewController {
private void onFlingEnd(boolean cancelled) {
mIsFlinging = false;
+ // No overshoot when the animation ends
+ setOverExpansionInternal(0, false /* isFromGesture */);
setAnimator(null);
mKeyguardStateController.notifyPanelFlingEnd();
if (!cancelled) {
@@ -644,7 +687,7 @@ public abstract class PanelViewController {
public void setExpandedHeight(float height) {
if (DEBUG) logf("setExpandedHeight(%.1f)", height);
- setExpandedHeightInternal(height + getOverExpansionPixels());
+ setExpandedHeightInternal(height);
}
protected void requestPanelHeightUpdate() {
@@ -662,7 +705,7 @@ public abstract class PanelViewController {
return;
}
- if (mHeightAnimator != null) {
+ if (mHeightAnimator != null && !mIsSpringBackAnimation) {
mPanelUpdateWhenAnimatorEnds = true;
return;
}
@@ -677,38 +720,24 @@ public abstract class PanelViewController {
return stackHeightFraction;
}
- // When the shade is flinged open, add space before sections for overscroll effect.
- private void maybeOverScrollForShadeFlingOpen(float height) {
- if (!mBar.isShadeOpening() || mFlingVelocity <= 0) {
- return;
- }
- final float padding = MathUtils.lerp(
- MIN_OVERSCROLL, MAX_OVERSCROLL, getStackHeightFraction(height));
- setSectionPadding(padding);
- }
-
public void setExpandedHeightInternal(float h) {
if (isNaN(h)) {
Log.wtf(TAG, "ExpandedHeight set to NaN");
}
- maybeOverScrollForShadeFlingOpen(h);
if (mExpandLatencyTracking && h != 0f) {
DejankUtils.postAfterTraversal(
() -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
mExpandLatencyTracking = false;
}
- float fhWithoutOverExpansion = getMaxPanelHeight() - getOverExpansionAmount();
+ float maxPanelHeight = getMaxPanelHeight();
if (mHeightAnimator == null) {
- float overExpansionPixels = Math.max(0, h - fhWithoutOverExpansion);
- if (getOverExpansionPixels() != overExpansionPixels && mTracking) {
- setOverExpansion(overExpansionPixels, true /* isPixels */);
+ if (mTracking) {
+ float overExpansionPixels = Math.max(0, h - maxPanelHeight);
+ setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
}
- mExpandedHeight = Math.min(h, fhWithoutOverExpansion) + getOverExpansionAmount();
+ mExpandedHeight = Math.min(h, maxPanelHeight);
} else {
mExpandedHeight = h;
- if (mOverExpandedBeforeFling) {
- setOverExpansion(Math.max(0, h - fhWithoutOverExpansion), false /* isPixels */);
- }
}
// If we are closing the panel and we are almost there due to a slow decelerating
@@ -720,7 +749,7 @@ public abstract class PanelViewController {
}
}
mExpandedFraction = Math.min(1f,
- fhWithoutOverExpansion == 0 ? 0 : mExpandedHeight / fhWithoutOverExpansion);
+ maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
onHeightUpdated(mExpandedHeight);
notifyBarPanelExpansionChanged();
}
@@ -731,16 +760,31 @@ public abstract class PanelViewController {
*/
protected abstract boolean isTrackingBlocked();
- protected abstract void setSectionPadding(float padding);
+ protected void setOverExpansion(float overExpansion) {
+ mOverExpansion = overExpansion;
+ }
- protected abstract void setOverExpansion(float overExpansion, boolean isPixels);
+ /**
+ * Set the current overexpansion
+ *
+ * @param overExpansion the amount of overexpansion to apply
+ * @param isFromGesture is this amount from a gesture and needs to be rubberBanded?
+ */
+ private void setOverExpansionInternal(float overExpansion, boolean isFromGesture) {
+ if (!isFromGesture) {
+ mLastGesturedOverExpansion = -1;
+ setOverExpansion(overExpansion);
+ } else if (mLastGesturedOverExpansion != overExpansion) {
+ mLastGesturedOverExpansion = overExpansion;
+ final float heightForFullOvershoot = mView.getHeight() / 3.0f;
+ float newExpansion = MathUtils.saturate(overExpansion / heightForFullOvershoot);
+ newExpansion = Interpolators.getOvershootInterpolation(newExpansion);
+ setOverExpansion(newExpansion * mPanelFlingOvershootAmount * 2.0f);
+ }
+ }
protected abstract void onHeightUpdated(float expandedHeight);
- protected abstract float getOverExpansionAmount();
-
- protected abstract float getOverExpansionPixels();
-
/**
* This returns the maximum height of the panel. Children should override this if their
* desired height is not the full height.
@@ -977,9 +1021,32 @@ public abstract class PanelViewController {
}
private ValueAnimator createHeightAnimator(float targetHeight) {
+ return createHeightAnimator(targetHeight, 0.0f /* performOvershoot */);
+ }
+
+ /**
+ * Create an animator that can also overshoot
+ *
+ * @param targetHeight the target height
+ * @param overshootAmount the amount of overshoot desired
+ */
+ private ValueAnimator createHeightAnimator(float targetHeight, float overshootAmount) {
+ float startExpansion = mOverExpansion;
ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, targetHeight);
animator.addUpdateListener(
- animation -> setExpandedHeightInternal((float) animation.getAnimatedValue()));
+ animation -> {
+ if (overshootAmount > 0.0f
+ // Also remove the overExpansion when collapsing
+ || (targetHeight == 0.0f && startExpansion != 0)) {
+ final float expansion = MathUtils.lerp(
+ startExpansion,
+ mPanelFlingOvershootAmount * overshootAmount,
+ Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ animator.getAnimatedFraction()));
+ setOverExpansionInternal(expansion, false /* isFromGesture */);
+ }
+ setExpandedHeightInternal((float) animation.getAnimatedValue());
+ });
return animator;
}
@@ -989,7 +1056,7 @@ public abstract class PanelViewController {
mExpandedFraction,
mExpandedFraction > 0f || mInstantExpanding
|| isPanelVisibleBecauseOfHeadsUp() || mTracking
- || mHeightAnimator != null);
+ || mHeightAnimator != null && !mIsSpringBackAnimation);
}
for (int i = 0; i < mExpansionListeners.size(); i++) {
mExpansionListeners.get(i).onPanelExpansionChanged(mExpandedFraction, mTracking);
@@ -1037,14 +1104,6 @@ public abstract class PanelViewController {
public abstract void resetViews(boolean animate);
-
- /**
- * @return whether "Clear all" button will be visible when the panel is fully expanded
- */
- protected abstract boolean fullyExpandedClearAllVisible();
-
- protected abstract boolean isClearAllVisible();
-
public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
mHeadsUpManager = headsUpManager;
}
@@ -1080,6 +1139,11 @@ public abstract class PanelViewController {
return new OnConfigurationChangedListener();
}
+ /**
+ * Set that the panel is currently opening and not fully opened or closed.
+ */
+ public abstract void setIsShadeOpening(boolean opening);
+
public class TouchHandler implements View.OnTouchListener {
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled || (mMotionAborted
@@ -1108,7 +1172,7 @@ public abstract class PanelViewController {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mStatusBar.userActivity();
- mAnimatingOnDown = mHeightAnimator != null;
+ mAnimatingOnDown = mHeightAnimator != null && !mIsSpringBackAnimation;
mMinExpandHeight = 0.0f;
mDownTime = SystemClock.uptimeMillis();
if (mAnimatingOnDown && mClosing && !mHintAnimationRunning) {
@@ -1227,10 +1291,10 @@ public abstract class PanelViewController {
mCollapsedAndHeadsUpOnDown =
isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp();
addMovement(event);
- if (!mGestureWaitForTouchSlop || (mHeightAnimator != null
- && !mHintAnimationRunning)) {
- mTouchSlopExceeded =
- (mHeightAnimator != null && !mHintAnimationRunning)
+ boolean regularHeightAnimationRunning = mHeightAnimator != null
+ && !mHintAnimationRunning && !mIsSpringBackAnimation;
+ if (!mGestureWaitForTouchSlop || regularHeightAnimationRunning) {
+ mTouchSlopExceeded = regularHeightAnimationRunning
|| mTouchSlopExceededBeforeDown;
cancelHeightAnimator();
onTrackingStarted();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index c0957c0aff81..29bb1f4ac7c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -26,6 +26,7 @@ import static com.android.systemui.statusbar.phone.BiometricUnlockController.MOD
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.hardware.biometrics.BiometricSourceType;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.KeyEvent;
@@ -768,9 +769,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private void wakeAndUnlockDejank() {
if (mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK
&& LatencyTracker.isEnabled(mContext)) {
- DejankUtils.postAfterTraversal(() ->
+ BiometricSourceType type = mBiometricUnlockController.getBiometricType();
+ DejankUtils.postAfterTraversal(() -> {
LatencyTracker.getInstance(mContext).onActionEnd(
- LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK));
+ type == BiometricSourceType.FACE
+ ? LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK
+ : LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
index b2ab30785b4e..14e513a0556d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
@@ -28,8 +28,8 @@ class StatusBarLaunchAnimatorController(
override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
- statusBar.onLaunchAnimationEnd(isExpandingFullyAbove)
statusBar.notificationPanelViewController.setIsLaunchAnimationRunning(false)
+ statusBar.onLaunchAnimationEnd(isExpandingFullyAbove)
}
override fun onLaunchAnimationProgress(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index f5dd19552b7f..7b7c17d08eda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -282,15 +282,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
boolean showOverLockscreen) {
mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey());
- // TODO: Some of this code may be able to move to NotificationEntryManager.
- String key = row.getEntry().getSbn().getKey();
- if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) {
- // Release the HUN notification to the shade.
- if (mPresenter.isPresenterFullyCollapsed()) {
- HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
- }
- }
-
final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
entry, row, controller, intent,
isActivityIntent, animate);
@@ -337,7 +328,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
// bypass work challenge
if (mStatusBarRemoteInputCallback.startWorkChallengeIfNecessary(userId,
intent.getIntentSender(), notificationKey)) {
- removeHUN(row);
+ removeHunAfterClick(row);
// Show work challenge, do not run PendingIntent and
// remove notification
collapseOnMainThread();
@@ -357,7 +348,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
final boolean canBubble = entry.canBubble();
if (canBubble) {
mLogger.logExpandingBubble(notificationKey);
- removeHUN(row);
+ removeHunAfterClick(row);
expandBubbleStackOnMainThread(entry);
} else {
startNotificationIntent(intent, fillInIntent, entry, row, animate, isActivityIntent);
@@ -508,9 +499,14 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
}, null, false /* afterKeyguardGone */);
}
- private void removeHUN(ExpandableNotificationRow row) {
+ private void removeHunAfterClick(ExpandableNotificationRow row) {
String key = row.getEntry().getSbn().getKey();
if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) {
+ // Release the HUN notification to the shade.
+ if (mPresenter.isPresenterFullyCollapsed()) {
+ HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(row, true);
+ }
+
// In most cases, when FLAG_AUTO_CANCEL is set, the notification will
// become canceled shortly by NoMan, but we can't assume that.
mHeadsUpManager.removeNotification(key, true /* releaseImmediately */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
index 1e3c123cfbc6..1212585d9829 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
@@ -31,7 +31,7 @@ public final class HeadsUpUtil {
* @param view The view to be set the flag to.
* @param clicked True to set as clicked. False to not-clicked.
*/
- public static void setIsClickedHeadsUpNotification(View view, boolean clicked) {
+ public static void setNeedsHeadsUpDisappearAnimationAfterClick(View view, boolean clicked) {
view.setTag(TAG_CLICKED_NOTIFICATION, clicked ? true : null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index 9d0cc6a00ec0..65f236b77a64 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -25,7 +25,6 @@ import android.provider.Settings;
import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
-import android.util.Log;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
@@ -143,10 +142,6 @@ public class QuickAccessWalletController {
*/
public void queryWalletCards(
QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
- if (!mWalletEnabled) {
- Log.w(TAG, "QuickAccessWallet is unavailable, unable to query cards.");
- return;
- }
int cardWidth =
mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width);
int cardHeight =
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index c6123e77076d..2dcc43cf60dc 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -19,11 +19,12 @@ package com.android.systemui.wallet.ui;
import static android.provider.Settings.ACTION_LOCKSCREEN_SETTINGS;
import android.content.Intent;
-import android.graphics.Color;
import android.graphics.drawable.Drawable;
+import android.hardware.biometrics.BiometricSourceType;
import android.os.Bundle;
import android.os.Handler;
import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.service.quickaccesswallet.WalletServiceEvent;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -33,6 +34,9 @@ import android.widget.Toolbar;
import androidx.annotation.NonNull;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -51,7 +55,8 @@ import javax.inject.Inject;
/**
* Displays Wallet carousel screen inside an activity.
*/
-public class WalletActivity extends LifecycleActivity {
+public class WalletActivity extends LifecycleActivity implements
+ QuickAccessWalletClient.WalletServiceEventListener {
private static final String TAG = "WalletActivity";
private final KeyguardStateController mKeyguardStateController;
@@ -61,8 +66,13 @@ public class WalletActivity extends LifecycleActivity {
private final Handler mHandler;
private final FalsingManager mFalsingManager;
private final UserTracker mUserTracker;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final StatusBarKeyguardViewManager mKeyguardViewManager;
+
+ private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
private WalletScreenController mWalletScreenController;
+ private QuickAccessWalletClient mWalletClient;
+ private boolean mHasRegisteredListener;
@Inject
public WalletActivity(
@@ -73,6 +83,7 @@ public class WalletActivity extends LifecycleActivity {
@Main Handler handler,
FalsingManager falsingManager,
UserTracker userTracker,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
StatusBarKeyguardViewManager keyguardViewManager) {
mKeyguardStateController = keyguardStateController;
mKeyguardDismissUtil = keyguardDismissUtil;
@@ -81,6 +92,7 @@ public class WalletActivity extends LifecycleActivity {
mHandler = handler;
mFalsingManager = falsingManager;
mUserTracker = userTracker;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardViewManager = keyguardViewManager;
}
@@ -102,21 +114,31 @@ public class WalletActivity extends LifecycleActivity {
getActionBar().setHomeActionContentDescription(R.string.accessibility_desc_close);
WalletView walletView = requireViewById(R.id.wallet_view);
- QuickAccessWalletClient walletClient = QuickAccessWalletClient.create(this);
+ mWalletClient = QuickAccessWalletClient.create(this);
mWalletScreenController = new WalletScreenController(
this,
walletView,
- walletClient,
+ mWalletClient,
mActivityStarter,
mExecutor,
mHandler,
mUserTracker,
mFalsingManager,
+ mKeyguardUpdateMonitor,
mKeyguardStateController);
+ mKeyguardUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onBiometricRunningStateChanged(
+ boolean running,
+ BiometricSourceType biometricSourceType) {
+ Log.d(TAG, "Biometric running state has changed.");
+ mWalletScreenController.queryWalletCards();
+ }
+ };
walletView.getAppButton().setOnClickListener(
v -> {
- if (walletClient.createWalletIntent() == null) {
+ if (mWalletClient.createWalletIntent() == null) {
Log.w(TAG, "Unable to create wallet app intent.");
return;
}
@@ -127,12 +149,12 @@ public class WalletActivity extends LifecycleActivity {
if (mKeyguardStateController.isUnlocked()) {
mActivityStarter.startActivity(
- walletClient.createWalletIntent(), true);
+ mWalletClient.createWalletIntent(), true);
finish();
} else {
mKeyguardDismissUtil.executeWhenUnlocked(() -> {
mActivityStarter.startActivity(
- walletClient.createWalletIntent(), true);
+ mWalletClient.createWalletIntent(), true);
finish();
return false;
}, false, true);
@@ -142,7 +164,9 @@ public class WalletActivity extends LifecycleActivity {
// Click the action button to re-render the screen when the device is unlocked.
walletView.setDeviceLockedActionOnClickListener(
v -> {
+ Log.d(TAG, "Wallet action button is clicked.");
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ Log.d(TAG, "False tap detected on wallet action button.");
return;
}
@@ -154,14 +178,23 @@ public class WalletActivity extends LifecycleActivity {
@Override
protected void onStart() {
super.onStart();
+ if (!mHasRegisteredListener) {
+ // Listener is registered even when device is locked. Should only be registered once.
+ mWalletClient.addWalletServiceEventListener(this);
+ mHasRegisteredListener = true;
+ }
mKeyguardStateController.addCallback(mWalletScreenController);
+ mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
}
@Override
protected void onResume() {
super.onResume();
mWalletScreenController.queryWalletCards();
- mKeyguardViewManager.requestFp(true, Color.BLACK);
+ mKeyguardViewManager.requestFp(
+ true,
+ Utils.getColorAttrDefaultColor(
+ this, com.android.internal.R.attr.colorAccentPrimary));
mKeyguardViewManager.requestFace(true);
}
@@ -178,6 +211,23 @@ public class WalletActivity extends LifecycleActivity {
return super.onCreateOptionsMenu(menu);
}
+ /**
+ * Implements {@link QuickAccessWalletClient.WalletServiceEventListener}. Called when the wallet
+ * application propagates an event, such as an NFC tap, to the quick access wallet view.
+ */
+ @Override
+ public void onWalletServiceEvent(WalletServiceEvent event) {
+ switch (event.getEventType()) {
+ case WalletServiceEvent.TYPE_NFC_PAYMENT_STARTED:
+ break;
+ case WalletServiceEvent.TYPE_WALLET_CARDS_UPDATED:
+ mWalletScreenController.queryWalletCards();
+ break;
+ default:
+ Log.w(TAG, "onWalletServiceEvent: Unknown event type");
+ }
+ }
+
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId();
@@ -197,7 +247,12 @@ public class WalletActivity extends LifecycleActivity {
@Override
protected void onDestroy() {
mKeyguardStateController.removeCallback(mWalletScreenController);
+ if (mKeyguardUpdateMonitorCallback != null) {
+ mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+ }
mWalletScreenController.onDismissed();
+ mWalletClient.removeWalletServiceEventListener(this);
+ mHasRegisteredListener = false;
super.onDestroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
index 8da80caefdd3..ab8ad7779689 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
@@ -30,7 +30,6 @@ import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.SelectWalletCardRequest;
import android.service.quickaccesswallet.WalletCard;
-import android.service.quickaccesswallet.WalletServiceEvent;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -40,6 +39,7 @@ import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -55,7 +55,6 @@ import java.util.concurrent.TimeUnit;
public class WalletScreenController implements
WalletCardCarousel.OnSelectionListener,
QuickAccessWalletClient.OnWalletCardsRetrievedCallback,
- QuickAccessWalletClient.WalletServiceEventListener,
KeyguardStateController.Callback {
private static final String TAG = "WalletScreenCtrl";
@@ -68,6 +67,7 @@ public class WalletScreenController implements
private final ActivityStarter mActivityStarter;
private final Executor mExecutor;
private final Handler mHandler;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardStateController mKeyguardStateController;
private final Runnable mSelectionRunnable = this::selectCard;
private final SharedPreferences mPrefs;
@@ -77,7 +77,6 @@ public class WalletScreenController implements
@VisibleForTesting String mSelectedCardId;
@VisibleForTesting boolean mIsDismissed;
- private boolean mHasRegisteredListener;
public WalletScreenController(
Context context,
@@ -88,6 +87,7 @@ public class WalletScreenController implements
Handler handler,
UserTracker userTracker,
FalsingManager falsingManager,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardStateController keyguardStateController) {
mContext = context;
mWalletClient = walletClient;
@@ -95,6 +95,7 @@ public class WalletScreenController implements
mExecutor = executor;
mHandler = handler;
mFalsingManager = falsingManager;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardStateController = keyguardStateController;
mPrefs = userTracker.getUserContext().getSharedPreferences(TAG, Context.MODE_PRIVATE);
mWalletView = walletView;
@@ -117,6 +118,7 @@ public class WalletScreenController implements
if (mIsDismissed) {
return;
}
+ Log.i(TAG, "Successfully retrieved wallet cards.");
List<WalletCard> walletCards = response.getWalletCards();
List<WalletCardViewInfo> data = new ArrayList<>(walletCards.size());
for (WalletCard card : walletCards) {
@@ -136,8 +138,13 @@ public class WalletScreenController implements
Log.w(TAG, "Invalid selected card index, showing empty state.");
showEmptyStateView();
} else {
+ boolean isUdfpsEnabled = mKeyguardUpdateMonitor.isUdfpsEnrolled()
+ && mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
mWalletView.showCardCarousel(
- data, selectedIndex, !mKeyguardStateController.isUnlocked());
+ data,
+ selectedIndex,
+ !mKeyguardStateController.isUnlocked(),
+ isUdfpsEnabled);
}
}
removeMinHeightAndRecordHeightOnLayout();
@@ -158,26 +165,6 @@ public class WalletScreenController implements
});
}
- /**
- * Implements {@link QuickAccessWalletClient.WalletServiceEventListener}. Called when the wallet
- * application propagates an event, such as an NFC tap, to the quick access wallet view.
- */
- @Override
- public void onWalletServiceEvent(WalletServiceEvent event) {
- if (mIsDismissed) {
- return;
- }
- switch (event.getEventType()) {
- case WalletServiceEvent.TYPE_NFC_PAYMENT_STARTED:
- break;
- case WalletServiceEvent.TYPE_WALLET_CARDS_UPDATED:
- queryWalletCards();
- break;
- default:
- Log.w(TAG, "onWalletServiceEvent: Unknown event type");
- }
- }
-
@Override
public void onKeyguardFadingAwayChanged() {
queryWalletCards();
@@ -236,11 +223,6 @@ public class WalletScreenController implements
if (cardWidthPx == 0 || cardHeightPx == 0) {
return;
}
- if (!mHasRegisteredListener) {
- // Listener is registered even when device is locked. Should only be registered once.
- mWalletClient.addWalletServiceEventListener(this);
- mHasRegisteredListener = true;
- }
mWalletView.show();
mWalletView.hideErrorMessage();
@@ -261,7 +243,6 @@ public class WalletScreenController implements
mSelectedCardId = null;
mHandler.removeCallbacks(mSelectionRunnable);
mWalletClient.notifyWalletDismissed();
- mWalletClient.removeWalletServiceEventListener(this);
mWalletView.animateDismissal();
// clear refs to the Wallet Activity
mContext = null;
@@ -282,7 +263,6 @@ public class WalletScreenController implements
mWalletView.hide();
mPrefs.edit().putInt(PREFS_WALLET_VIEW_HEIGHT, 0).apply();
} else {
- logo.setTint(mContext.getColor(R.color.GM2_grey_900));
mWalletView.showEmptyStateView(
logo,
logoContentDesc,
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index bf146b6cd02f..8412a8ae966e 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -63,6 +63,7 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
private final ViewGroup mEmptyStateView;
private CharSequence mCenterCardText;
private boolean mIsDeviceLocked = false;
+ private boolean mIsUdfpsEnabled = false;
private OnClickListener mDeviceLockedActionOnClickListener;
public WalletView(Context context) {
@@ -108,7 +109,7 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
mCardLabel.setText(centerCardText);
mIcon.setImageDrawable(centerCardIcon);
}
- renderActionButton(centerCard, mIsDeviceLocked);
+ renderActionButton(centerCard, mIsDeviceLocked, mIsUdfpsEnabled);
if (TextUtils.equals(centerCardText, getLabelText(nextCard))) {
mCardLabel.setAlpha(1f);
} else {
@@ -128,15 +129,19 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
* @param isDeviceLocked indicates whether the device is locked.
*/
void showCardCarousel(
- List<WalletCardViewInfo> data, int selectedIndex, boolean isDeviceLocked) {
+ List<WalletCardViewInfo> data,
+ int selectedIndex,
+ boolean isDeviceLocked,
+ boolean isUdfpsEnabled) {
boolean shouldAnimate =
mCardCarousel.setData(data, selectedIndex, mIsDeviceLocked != isDeviceLocked);
mIsDeviceLocked = isDeviceLocked;
+ mIsUdfpsEnabled = isUdfpsEnabled;
mCardCarouselContainer.setVisibility(VISIBLE);
mErrorView.setVisibility(GONE);
mEmptyStateView.setVisibility(GONE);
mIcon.setImageDrawable(getHeaderIcon(mContext, data.get(selectedIndex)));
- renderActionButton(data.get(selectedIndex), isDeviceLocked);
+ renderActionButton(data.get(selectedIndex), isDeviceLocked, mIsUdfpsEnabled);
if (shouldAnimate) {
animateViewsShown(mIcon, mCardLabel, mActionButton);
}
@@ -161,10 +166,12 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
OnClickListener clickListener) {
mEmptyStateView.setVisibility(VISIBLE);
mErrorView.setVisibility(GONE);
- mCardCarouselContainer.setVisibility(GONE);
+ mCardCarousel.setVisibility(GONE);
+ mIcon.setImageDrawable(logo);
+ mIcon.setContentDescription(logoContentDescription);
+ mCardLabel.setText(R.string.wallet_empty_state_label);
ImageView logoView = mEmptyStateView.requireViewById(R.id.empty_state_icon);
- logoView.setImageDrawable(logo);
- logoView.setContentDescription(logoContentDescription);
+ logoView.setImageDrawable(mContext.getDrawable(R.drawable.ic_qs_plus));
mEmptyStateView.<TextView>requireViewById(R.id.empty_state_title).setText(label);
mEmptyStateView.setOnClickListener(clickListener);
}
@@ -238,13 +245,14 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
return icon;
}
- private void renderActionButton(WalletCardViewInfo walletCard, boolean isDeviceLocked) {
+ private void renderActionButton(
+ WalletCardViewInfo walletCard, boolean isDeviceLocked, boolean isUdfpsEnabled) {
CharSequence actionButtonText = getActionButtonText(walletCard);
- if (isDeviceLocked) {
+ if (!isUdfpsEnabled && isDeviceLocked) {
mActionButton.setVisibility(VISIBLE);
mActionButton.setText(R.string.wallet_action_button_label_unlock);
mActionButton.setOnClickListener(mDeviceLockedActionOnClickListener);
- } else if (actionButtonText != null) {
+ } else if (!isDeviceLocked && actionButtonText != null) {
mActionButton.setText(actionButtonText);
mActionButton.setVisibility(VISIBLE);
mActionButton.setOnClickListener(v -> {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 83c2227ffc12..6ec14fe46223 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -32,6 +32,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -59,6 +61,8 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
SmartspaceTransitionController mSmartSpaceTransitionController;
@Mock
UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ @Captor
+ private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
private KeyguardStatusViewController mController;
@@ -90,4 +94,26 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
mController.dozeTimeTick();
verify(mKeyguardClockSwitchController).refresh();
}
+
+ @Test
+ public void timeFormatUpdateNotifiesClockSwitchController() {
+ mController.onViewAttached();
+
+ verify(mKeyguardUpdateMonitor).registerCallback(
+ mKeyguardUpdateMonitorCallbackCaptor.capture());
+
+ mKeyguardUpdateMonitorCallbackCaptor.getValue().onTimeFormatChanged("");
+ verify(mKeyguardClockSwitchController).refreshFormat();
+ }
+
+ @Test
+ public void userChangeNotifiesClockSwitchController() {
+ mController.onViewAttached();
+
+ verify(mKeyguardUpdateMonitor).registerCallback(
+ mKeyguardUpdateMonitorCallbackCaptor.capture());
+
+ mKeyguardUpdateMonitorCallbackCaptor.getValue().onUserSwitchComplete(0);
+ verify(mKeyguardClockSwitchController).refreshFormat();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index d63c529778b8..46a60dc47e7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -95,6 +95,7 @@ import android.service.notification.ConversationChannelWrapper;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
+import android.text.TextUtils;
import androidx.preference.PreferenceManager;
import androidx.test.filters.SmallTest;
@@ -112,6 +113,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
+import com.android.wm.shell.bubbles.Bubbles;
import org.junit.Before;
import org.junit.Test;
@@ -224,6 +226,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
private NotificationManager mNotificationManager;
@Mock
private NotificationManager.Policy mNotificationPolicy;
+ @Mock
+ private Bubbles mBubbles;
@Captor
private ArgumentCaptor<NotificationHandler> mListenerCaptor;
@@ -242,7 +246,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
mManager = new PeopleSpaceWidgetManager(mContext, mAppWidgetManager, mIPeopleManager,
mPeopleManager, mLauncherApps, mNotificationEntryManager, mPackageManager,
- mUserManager, mINotificationManager, mNotificationManager, mFakeExecutor);
+ Optional.of(mBubbles), mUserManager, mINotificationManager, mNotificationManager,
+ mFakeExecutor);
mManager.attach(mListenerService);
verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
@@ -267,6 +272,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
INTERRUPTION_FILTER_ALL);
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mBubbles.isBubbleNotificationSuppressedFromShade(any(), any())).thenReturn(false);
when(mMockContext.getPackageName()).thenReturn(TEST_PACKAGE_A);
when(mMockContext.getUserId()).thenReturn(0);
@@ -1193,6 +1199,28 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
}
@Test
+ public void testAugmentTileFromNotificationEntryManager_notificationHidden() {
+ when(mBubbles.isBubbleNotificationSuppressedFromShade(any(), any())).thenReturn(true);
+ PeopleSpaceTile tile =
+ new PeopleSpaceTile
+ .Builder(SHORTCUT_ID, "userName", ICON, new Intent())
+ .setPackageName(TEST_PACKAGE_A)
+ .setUserHandle(new UserHandle(0))
+ .build();
+ when(mNotificationEntryManager.getVisibleNotifications())
+ .thenReturn(List.of(mNotificationEntry));
+
+ PeopleSpaceTile actual =
+ mManager.augmentTileFromNotificationEntryManager(tile,
+ Optional.of(WIDGET_ID_WITH_SHORTCUT));
+
+ assertThat(TextUtils.isEmpty(actual.getNotificationContent())).isTrue();
+
+ verify(mNotificationEntryManager, times(1))
+ .getVisibleNotifications();
+ }
+
+ @Test
public void testUpdateWidgetsOnStateChange() {
mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index b09afab3d242..09b042700dd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -46,7 +46,6 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.QuickAccessWalletService;
@@ -75,8 +74,6 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
-import com.google.common.util.concurrent.MoreExecutors;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -126,8 +123,6 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
@Captor
ArgumentCaptor<Intent> mIntentCaptor;
@Captor
- ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
- @Captor
ArgumentCaptor<QuickAccessWalletClient.OnWalletCardsRetrievedCallback> mCallbackCaptor;
private Context mSpiedContext;
@@ -163,7 +158,6 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
mKeyguardStateController,
mPackageManager,
mSecureSettings,
- MoreExecutors.directExecutor(),
mController,
mFeatureFlags);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
index d95063f07c2b..3a4bc699b967 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
@@ -65,7 +65,6 @@ public class ScrollCaptureClientTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- Context context = InstrumentationRegistry.getInstrumentation().getContext();
mWm = mock(IWindowManager.class);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
new file mode 100644
index 000000000000..c74437f5ad94
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
@@ -0,0 +1,99 @@
+package com.android.systemui.statusbar.notification
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController
+import com.android.systemui.statusbar.policy.HeadsUpUtil
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
+ @Mock lateinit var notificationShadeWindowViewController: NotificationShadeWindowViewController
+ @Mock lateinit var notificationListContainer: NotificationListContainer
+ @Mock lateinit var headsUpManager: HeadsUpManagerPhone
+
+ private lateinit var notificationTestHelper: NotificationTestHelper
+ private lateinit var notification: ExpandableNotificationRow
+ private lateinit var controller: NotificationLaunchAnimatorController
+
+ private val notificationKey: String
+ get() = notification.entry.sbn.key
+
+ @get:Rule val rule = MockitoJUnit.rule()
+
+ @Before
+ fun setUp() {
+ allowTestableLooperAsMainThread()
+ notificationTestHelper =
+ NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+ notification = notificationTestHelper.createRow()
+ controller = NotificationLaunchAnimatorController(
+ notificationShadeWindowViewController,
+ notificationListContainer,
+ headsUpManager,
+ notification
+ )
+ }
+
+ private fun flagNotificationAsHun() {
+ `when`(headsUpManager.isAlerting(notificationKey)).thenReturn(true)
+ }
+
+ @Test
+ fun testHunIsRemovedIfWeDontAnimateLaunch() {
+ flagNotificationAsHun()
+ controller.onIntentStarted(willAnimate = false)
+
+ assertTrue(HeadsUpUtil.isClickedHeadsUpNotification(notification))
+ assertFalse(notification.entry.isExpandAnimationRunning)
+ verify(headsUpManager).removeNotification(
+ notificationKey, true /* releaseImmediately */, true /* animate */)
+ }
+
+ @Test
+ fun testHunIsRemovedWhenAnimationIsCancelled() {
+ flagNotificationAsHun()
+ controller.onLaunchAnimationCancelled()
+
+ assertTrue(HeadsUpUtil.isClickedHeadsUpNotification(notification))
+ assertFalse(notification.entry.isExpandAnimationRunning)
+ verify(headsUpManager).removeNotification(
+ notificationKey, true /* releaseImmediately */, true /* animate */)
+ }
+
+ @Test
+ fun testHunIsRemovedWhenAnimationEnds() {
+ flagNotificationAsHun()
+ controller.onLaunchAnimationEnd(isExpandingFullyAbove = true)
+
+ assertFalse(HeadsUpUtil.isClickedHeadsUpNotification(notification))
+ assertFalse(notification.entry.isExpandAnimationRunning)
+ verify(headsUpManager).removeNotification(
+ notificationKey, true /* releaseImmediately */, false /* animate */)
+ }
+
+ @Test
+ fun testNotificationIsExpandingDuringAnimation() {
+ controller.onIntentStarted(willAnimate = true)
+
+ assertTrue(notification.entry.isExpandAnimationRunning)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index ffb53a8b2e11..4b5657afe02f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -638,8 +638,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
public void testCancelSwipeWhileLocked_notifiesKeyguardState() {
mStatusBarStateController.setState(KEYGUARD);
- mNotificationPanelViewController.setOverExpansion(100f, true);
-
// Fling expanded (cancelling the keyguard exit swipe). We should notify keyguard state that
// the fling occurred and did not dismiss the keyguard.
mNotificationPanelViewController.flingToHeight(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
index 33666bc5b462..23abce086728 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
@@ -21,9 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -127,17 +125,7 @@ public class QuickAccessWalletControllerTest extends SysuiTestCase {
}
@Test
- public void queryWalletCards_walletNotEnabled_notQuery() {
- when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
-
- mController.queryWalletCards(mCardsRetriever);
-
- verify(mQuickAccessWalletClient, never()).getWalletCards(any(), any(), any());
- }
-
- @Test
public void queryWalletCards_walletEnabled_queryCards() {
- mController.updateWalletPreference();
mController.queryWalletCards(mCardsRetriever);
verify(mQuickAccessWalletClient)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
index cd1eb1c4468e..e6c740b3a263 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
@@ -20,13 +20,9 @@ import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.app.PendingIntent;
@@ -38,17 +34,16 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.QuickAccessWalletService;
import android.service.quickaccesswallet.WalletCard;
-import android.service.quickaccesswallet.WalletServiceEvent;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -94,15 +89,13 @@ public class WalletScreenControllerTest extends SysuiTestCase {
@Mock
FalsingManager mFalsingManager;
@Mock
+ KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
KeyguardStateController mKeyguardStateController;
@Captor
ArgumentCaptor<Intent> mIntentCaptor;
@Captor
- ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
- @Captor
ArgumentCaptor<QuickAccessWalletClient.OnWalletCardsRetrievedCallback> mCallbackCaptor;
- @Captor
- ArgumentCaptor<QuickAccessWalletClient.WalletServiceEventListener> mListenerCaptor;
private WalletScreenController mController;
private TestableLooper mTestableLooper;
@@ -119,6 +112,8 @@ public class WalletScreenControllerTest extends SysuiTestCase {
when(mWalletClient.getServiceLabel()).thenReturn(SERVICE_LABEL);
when(mWalletClient.createWalletIntent()).thenReturn(mWalletIntent);
when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(false);
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
mController = new WalletScreenController(
mContext,
mWalletView,
@@ -128,10 +123,61 @@ public class WalletScreenControllerTest extends SysuiTestCase {
new Handler(mTestableLooper.getLooper()),
mUserTracker,
mFalsingManager,
+ mKeyguardUpdateMonitor,
mKeyguardStateController);
}
@Test
+ public void queryCards_deviceLocked_udfpsEnabled_hideUnlockButton() {
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(true);
+ when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+ GetWalletCardsResponse response =
+ new GetWalletCardsResponse(
+ Collections.singletonList(createWalletCard(mContext)), 0);
+
+ mController.queryWalletCards();
+ mTestableLooper.processAllMessages();
+
+ verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
+
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
+ mCallbackCaptor.getValue();
+
+ assertEquals(mController, callback);
+
+ callback.onWalletCardsRetrieved(response);
+ mTestableLooper.processAllMessages();
+
+ assertEquals(VISIBLE, mWalletView.getCardCarouselContainer().getVisibility());
+ assertEquals(GONE, mWalletView.getActionButton().getVisibility());
+ }
+
+ @Test
+ public void queryCards_deviceLocked_udfpsNotEnabled_showUnlockButton() {
+ when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+ GetWalletCardsResponse response =
+ new GetWalletCardsResponse(
+ Collections.singletonList(createWalletCard(mContext)), 0);
+
+ mController.queryWalletCards();
+ mTestableLooper.processAllMessages();
+
+ verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
+
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
+ mCallbackCaptor.getValue();
+
+ assertEquals(mController, callback);
+
+ callback.onWalletCardsRetrieved(response);
+ mTestableLooper.processAllMessages();
+
+ assertEquals(VISIBLE, mWalletView.getCardCarouselContainer().getVisibility());
+ assertEquals(VISIBLE, mWalletView.getActionButton().getVisibility());
+ }
+
+ @Test
public void queryCards_hasCards_showCarousel_activeCard() {
GetWalletCardsResponse response =
new GetWalletCardsResponse(
@@ -250,7 +296,7 @@ public class WalletScreenControllerTest extends SysuiTestCase {
callback.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
- assertEquals(GONE, mWalletView.getCardCarouselContainer().getVisibility());
+ assertEquals(GONE, mWalletView.getCardCarousel().getVisibility());
assertEquals(VISIBLE, mWalletView.getEmptyStateView().getVisibility());
assertEquals(GONE, mWalletView.getErrorView().getVisibility());
}
@@ -267,7 +313,7 @@ public class WalletScreenControllerTest extends SysuiTestCase {
mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
- assertEquals(GONE, mWalletView.getCardCarouselContainer().getVisibility());
+ assertEquals(GONE, mWalletView.getCardCarousel().getVisibility());
assertEquals(VISIBLE, mWalletView.getEmptyStateView().getVisibility());
assertEquals(GONE, mWalletView.getErrorView().getVisibility());
}
@@ -292,40 +338,6 @@ public class WalletScreenControllerTest extends SysuiTestCase {
}
@Test
- public void onWalletServiceEvent_nfcPaymentStart_doNothing() {
- WalletServiceEvent event =
- new WalletServiceEvent(WalletServiceEvent.TYPE_NFC_PAYMENT_STARTED);
-
- mController.onWalletServiceEvent(event);
- mTestableLooper.processAllMessages();
-
- assertNull(mController.mSelectedCardId);
- assertFalse(mController.mIsDismissed);
- verifyZeroInteractions(mWalletClient);
- }
-
- @Test
- public void onWalletServiceEvent_walletCardsUpdate_queryCards() {
- mController.queryWalletCards();
-
- verify(mWalletClient).addWalletServiceEventListener(mListenerCaptor.capture());
-
- WalletServiceEvent event =
- new WalletServiceEvent(WalletServiceEvent.TYPE_WALLET_CARDS_UPDATED);
-
- QuickAccessWalletClient.WalletServiceEventListener listener = mListenerCaptor.getValue();
- listener.onWalletServiceEvent(event);
- mTestableLooper.processAllMessages();
-
- verify(mWalletClient, times(2))
- .getWalletCards(any(), mRequestCaptor.capture(), mCallbackCaptor.capture());
-
- GetWalletCardsRequest request = mRequestCaptor.getValue();
-
- assertEquals(MAX_CARDS, request.getMaxCards());
- }
-
- @Test
public void onKeyguardFadingAwayChanged_queryCards() {
mController.onKeyguardFadingAwayChanged();
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values/strings.xml
index a65fd43b7415..49010dab934f 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that masks the display cutout, i.e. avoid apps in cutout region.-->
- <string name="display_cutout_emulation_overlay">Hide (avoid apps in cutout region)</string>
+ <string name="display_cutout_emulation_overlay">Render apps below cutout area</string>
</resources>
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index afaddd9c418e..517a8294de9f 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -250,6 +250,14 @@ public final class ActiveServices {
final ArrayList<ServiceRecord> mPendingFgsNotifications = new ArrayList<>();
/**
+ * Whether there is a rate limit that suppresses immediate re-deferral of new FGS
+ * notifications from each app. On by default, disabled only by shell command for
+ * test-suite purposes. To disable the behavior more generally, use the usual
+ * DeviceConfig mechanism to set the rate limit interval to zero.
+ */
+ private boolean mFgsDeferralRateLimited = true;
+
+ /**
* Uptime at which a given uid becomes eliglible again for FGS notification deferral
*/
final SparseLongArray mFgsDeferralEligible = new SparseLongArray();
@@ -2142,8 +2150,10 @@ public final class ActiveServices {
}
}
- final long nextEligible = when + mAm.mConstants.mFgsNotificationDeferralExclusionTime;
- mFgsDeferralEligible.put(uid, nextEligible);
+ if (mFgsDeferralRateLimited) {
+ final long nextEligible = when + mAm.mConstants.mFgsNotificationDeferralExclusionTime;
+ mFgsDeferralEligible.put(uid, nextEligible);
+ }
r.fgDisplayTime = when;
r.mFgsNotificationDeferred = true;
r.mFgsNotificationShown = false;
@@ -2204,6 +2214,38 @@ public final class ActiveServices {
}
};
+ /**
+ * Suppress or reenable the rate limit on foreground service notification deferral.
+ * Invoked from the activity manager shell command.
+ *
+ * @param enable false to suppress rate-limit policy; true to reenable it.
+ */
+ boolean enableFgsNotificationRateLimitLocked(final boolean enable) {
+ if (enable != mFgsDeferralRateLimited) {
+ mFgsDeferralRateLimited = enable;
+ if (!enable) {
+ // make sure to reset any active rate limiting
+ mFgsDeferralEligible.clear();
+ }
+ }
+ return enable;
+ }
+
+ private void removeServiceNotificationDeferralsLocked(String packageName,
+ final @UserIdInt int userId) {
+ for (int i = mPendingFgsNotifications.size() - 1; i >= 0; i--) {
+ final ServiceRecord r = mPendingFgsNotifications.get(i);
+ if (userId == r.userId
+ && r.appInfo.packageName.equals(packageName)) {
+ mPendingFgsNotifications.remove(i);
+ if (DEBUG_FOREGROUND_SERVICE) {
+ Slog.d(TAG_SERVICE, "Removing notification deferral for "
+ + r);
+ }
+ }
+ }
+ }
+
private void maybeLogFGSStateEnteredLocked(ServiceRecord r) {
if (r.mLogEntering) {
logFGSStateChangeLocked(r,
@@ -4689,6 +4731,7 @@ public final class ActiveServices {
}
}
removeServiceRestartBackoffEnabledLocked(packageName);
+ removeServiceNotificationDeferralsLocked(packageName, userId);
}
void cleanUpServices(int userId, ComponentName component, Intent baseIntent) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6b0e2db3f218..86b528781699 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17066,6 +17066,19 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
+ * Suppress or reenable the rate limit on foreground service notification deferral.
+ * @param enable false to suppress rate-limit policy; true to reenable it.
+ */
+ @Override
+ public boolean enableFgsNotificationRateLimit(boolean enable) {
+ enforceCallingPermission(permission.WRITE_DEVICE_CONFIG,
+ "enableFgsNotificationRateLimit");
+ synchronized (this) {
+ return mServices.enableFgsNotificationRateLimitLocked(enable);
+ }
+ }
+
+ /**
* Holds the AM lock for the specified amount of milliseconds.
* Intended for use by the tests that need to imitate lock contention.
* The token should be obtained by
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index f2762fc965ee..0757e7b6bd7d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -230,6 +230,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
return runBugReport(pw);
case "force-stop":
return runForceStop(pw);
+ case "fgs-notification-rate-limit":
+ return runFgsNotificationRateLimit(pw);
case "crash":
return runCrash(pw);
case "kill":
@@ -1103,6 +1105,24 @@ final class ActivityManagerShellCommand extends ShellCommand {
return 0;
}
+ int runFgsNotificationRateLimit(PrintWriter pw) throws RemoteException {
+ final String toggleValue = getNextArgRequired();
+ final boolean enable;
+ switch (toggleValue) {
+ case "enable":
+ enable = true;
+ break;
+ case "disable":
+ enable = false;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Argument must be either 'enable' or 'disable'");
+ }
+ mInterface.enableFgsNotificationRateLimit(enable);
+ return 0;
+ }
+
int runCrash(PrintWriter pw) throws RemoteException {
int userId = UserHandle.USER_ALL;
@@ -3303,6 +3323,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" when done to select where it should be delivered. Options are:");
pw.println(" --progress: will launch a notification right away to show its progress.");
pw.println(" --telephony: will dump only telephony sections.");
+ pw.println(" fgs-notification-rate-limit {enable | disable}");
+ pw.println(" Enable/disable rate limit on FGS notification deferral policy.");
pw.println(" force-stop [--user <USER_ID> | all | current] <PACKAGE>");
pw.println(" Completely stop the given application package.");
pw.println(" crash [--user <USER_ID>] <PACKAGE|PID>");
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a68364e943cf..2a1c055b7313 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -4483,8 +4483,9 @@ public class AppOpsService extends IAppOpsService.Stub {
// Special case for the shell which is a package but should be able
// to bypass app attribution tag restrictions.
if (pkgUid != UserHandle.getAppId(uid)) {
+ String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
throw new SecurityException("Specified package " + packageName + " under uid "
- + UserHandle.getAppId(uid) + " but it is really " + pkgUid);
+ + UserHandle.getAppId(uid) + otherUidMessage);
}
return RestrictionBypass.UNRESTRICTED;
}
@@ -4544,8 +4545,9 @@ public class AppOpsService extends IAppOpsService.Stub {
}
if (pkgUid != uid) {
+ String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
throw new SecurityException("Specified package " + packageName + " under uid " + uid
- + " but it is really " + pkgUid);
+ + otherUidMessage);
}
return bypass;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 125cfd2e134d..edd30bc6b333 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -27,6 +27,7 @@ import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
@@ -46,6 +47,7 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
private static final String TAG = "FingerprintEnrollClient";
+ @NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private final ISidefpsController mSidefpsController;
@@ -58,12 +60,15 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int sensorId,
+ @NonNull FingerprintSensorPropertiesInternal sensorProps,
@Nullable IUdfpsOverlayController udfpsOvelayController,
@Nullable ISidefpsController sidefpsController,
int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason) {
+ // UDFPS enroll vibrations are handled in SystemUI
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
0 /* timeoutSec */, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
- true /* shouldVibrate */);
+ !sensorProps.isAnyUdfpsType() /* shouldVibrate */);
+ mSensorProps = sensorProps;
mUdfpsOverlayController = udfpsOvelayController;
mSidefpsController = sidefpsController;
mMaxTemplatesPerUser = maxTemplatesPerUser;
@@ -90,7 +95,8 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
public void onAcquired(@FingerprintAcquired int acquiredInfo, int vendorCode) {
// For UDFPS, notify SysUI that the illumination can be turned off.
// See AcquiredInfo#GOOD and AcquiredInfo#RETRYING_CAPTURE
- if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD) {
+ if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD
+ && mSensorProps.isAnyUdfpsType()) {
UdfpsHelper.onAcquiredGood(getSensorId(), mUdfpsOverlayController);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 293b9e41a169..096c3111d35c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -340,6 +340,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
+ mSensors.get(sensorId).getSensorProperties(),
mUdfpsOverlayController, mSidefpsController, maxTemplatesPerUser, enrollReason);
scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() {
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index c97095d8a54e..3369dcd67b4d 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -32,6 +32,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.content.pm.parsing.ParsingPackageUtils;
import android.os.Binder;
@@ -45,6 +46,7 @@ import android.util.ArraySet;
import android.util.Singleton;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.apk.ApkSignatureVerifier;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -52,6 +54,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.utils.TimingsTraceAndSlog;
import com.google.android.collect.Lists;
@@ -390,9 +393,10 @@ public abstract class ApexManager {
throws RemoteException;
/**
- * Performs a non-staged install of an APEX package with given {@code packagePath}.
+ * Performs a non-staged install of the given {@code apexFile}.
*/
- abstract void installPackage(String packagePath) throws PackageManagerException;
+ abstract void installPackage(File apexFile, PackageParser2 packageParser)
+ throws PackageManagerException;
/**
* Dumps various state information to the provided {@link PrintWriter} object.
@@ -979,12 +983,80 @@ public abstract class ApexManager {
waitForApexService().reserveSpaceForCompressedApex(infoList);
}
+ private SigningDetails getSigningDetails(PackageInfo pkg) throws PackageManagerException {
+ int minSignatureScheme =
+ ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
+ pkg.applicationInfo.targetSdkVersion);
+ try {
+ return ApkSignatureVerifier.verify(pkg.applicationInfo.sourceDir,
+ minSignatureScheme);
+ } catch (PackageParserException e) {
+ throw PackageManagerException.from(e);
+ }
+ }
+
+ private void checkApexSignature(PackageInfo existingApexPkg, PackageInfo newApexPkg)
+ throws PackageManagerException {
+ final SigningDetails existingSigningDetails = getSigningDetails(existingApexPkg);
+ final SigningDetails newSigningDetails = getSigningDetails(newApexPkg);
+ if (!newSigningDetails.checkCapability(existingSigningDetails,
+ SigningDetails.CertCapabilities.INSTALLED_DATA)) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+ "APK container signature of " + newApexPkg.applicationInfo.sourceDir
+ + " is not compatible with currently installed on device");
+ }
+ }
+
+ private void checkDowngrade(PackageInfo existingApexPkg, PackageInfo newApexPkg)
+ throws PackageManagerException {
+ final long currentVersionCode = existingApexPkg.applicationInfo.longVersionCode;
+ final long newVersionCode = newApexPkg.applicationInfo.longVersionCode;
+ if (currentVersionCode > newVersionCode) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE,
+ "Downgrade of APEX package " + newApexPkg.packageName
+ + " is not allowed");
+ }
+ }
+
@Override
- void installPackage(String packagePath) throws PackageManagerException {
+ void installPackage(File apexFile, PackageParser2 packageParser)
+ throws PackageManagerException {
try {
- // TODO(b/187864524): do pre-install verification.
- waitForApexService().installAndActivatePackage(packagePath);
- // TODO(b/187864524): update mAllPackagesCache.
+ final int flags = PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNING_CERTIFICATES
+ | PackageManager.GET_SIGNATURES;
+ final ParsedPackage parsedPackage = packageParser.parsePackage(
+ apexFile, flags, /* useCaches= */ false);
+ final PackageInfo newApexPkg = PackageInfoWithoutStateUtils.generate(parsedPackage,
+ /* apexInfo= */ null, flags);
+ if (newApexPkg == null) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INVALID_APK,
+ "Failed to generate package info for " + apexFile.getAbsolutePath());
+ }
+ final PackageInfo existingApexPkg = getPackageInfo(newApexPkg.packageName,
+ MATCH_ACTIVE_PACKAGE);
+ if (existingApexPkg == null) {
+ Slog.w(TAG, "Attempting to install new APEX package " + newApexPkg.packageName);
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED,
+ "It is forbidden to install new APEX packages");
+ }
+ checkApexSignature(existingApexPkg, newApexPkg);
+ checkDowngrade(existingApexPkg, newApexPkg);
+ ApexInfo apexInfo = waitForApexService().installAndActivatePackage(
+ apexFile.getAbsolutePath());
+ final ParsedPackage parsedPackage2 = packageParser.parsePackage(
+ new File(apexInfo.modulePath), flags, /* useCaches= */ false);
+ final PackageInfo finalApexPkg = PackageInfoWithoutStateUtils.generate(
+ parsedPackage, apexInfo, flags);
+ // Installation was successful, time to update mAllPackagesCache
+ synchronized (mLock) {
+ for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
+ if (mAllPackagesCache.get(i).equals(existingApexPkg)) {
+ mAllPackagesCache.set(i, finalApexPkg);
+ break;
+ }
+ }
+ }
} catch (RemoteException e) {
throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"apexservice not available");
@@ -1262,7 +1334,7 @@ public abstract class ApexManager {
}
@Override
- void installPackage(String packagePath) {
+ void installPackage(File apexFile, PackageParser2 packageParser) {
throw new UnsupportedOperationException("APEX updates are not supported");
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 1f0a8caa0ccf..0b63b7ddef85 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -653,13 +653,20 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
- if (mBypassNextStagedInstallerCheck) {
- mBypassNextStagedInstallerCheck = false;
- } else if (!isStagedInstallerAllowed(requestedInstallerPackageName)) {
+ if (!mBypassNextStagedInstallerCheck
+ && !isStagedInstallerAllowed(requestedInstallerPackageName)) {
throw new SecurityException("Installer not allowed to commit staged install");
}
}
+ if (isApex && !isCalledBySystemOrShell(callingUid)) {
+ if (!mBypassNextStagedInstallerCheck
+ && !isStagedInstallerAllowed(requestedInstallerPackageName)) {
+ throw new SecurityException(
+ "Installer not allowed to commit non-staged APEX install");
+ }
+ }
+ mBypassNextStagedInstallerCheck = false;
if (!params.isMultiPackage) {
// Only system components can circumvent runtime permissions when installing.
if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index be2a63d3f11e..d58a6aa53ae7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2335,11 +2335,11 @@ public class PackageManagerService extends IPackageManager.Stub
List<CrossProfileIntentFilter> matchingFilters =
getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
// Check for results that need to skip the current profile.
- ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
- resolvedType, flags, userId);
- if (xpResolveInfo != null) {
+ ResolveInfo skipProfileInfo = querySkipCurrentProfileIntents(matchingFilters,
+ intent, resolvedType, flags, userId);
+ if (skipProfileInfo != null) {
List<ResolveInfo> xpResult = new ArrayList<>(1);
- xpResult.add(xpResolveInfo);
+ xpResult.add(skipProfileInfo);
return new QueryIntentActivitiesResult(
applyPostResolutionFilter(
filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
@@ -2354,54 +2354,55 @@ public class PackageManagerService extends IPackageManager.Stub
false /*skipPackageCheck*/, flags);
// Check for cross profile results.
boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
- xpResolveInfo = queryCrossProfileIntents(
+ CrossProfileDomainInfo specificXpInfo = queryCrossProfileIntents(
matchingFilters, intent, resolvedType, flags, userId,
hasNonNegativePriorityResult);
- if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
- boolean isVisibleToUser = filterIfNotSystemUser(
- Collections.singletonList(xpResolveInfo), userId).size() > 0;
- if (isVisibleToUser) {
- result.add(xpResolveInfo);
- sortResult = true;
- }
- }
if (intent.hasWebURI()) {
- CrossProfileDomainInfo xpDomainInfo = null;
+ CrossProfileDomainInfo generalXpInfo = null;
final UserInfo parent = getProfileParent(userId);
if (parent != null) {
- xpDomainInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType,
+ generalXpInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType,
flags, userId, parent.id);
}
- if (xpDomainInfo != null) {
- if (xpResolveInfo != null) {
- // If we didn't remove it, the cross-profile ResolveInfo would be twice
- // in the result.
- result.remove(xpResolveInfo);
- }
- if (result.size() == 0 && !addInstant) {
+
+ // Generalized cross profile intents take precedence over specific.
+ // Note that this is the opposite of the intuitive order.
+ CrossProfileDomainInfo prioritizedXpInfo =
+ generalXpInfo != null ? generalXpInfo : specificXpInfo;
+
+ if (!addInstant) {
+ if (result.isEmpty() && prioritizedXpInfo != null) {
// No result in current profile, but found candidate in parent user.
// And we are not going to add ephemeral app, so we can return the
// result straight away.
- result.add(xpDomainInfo.resolveInfo);
+ result.add(prioritizedXpInfo.resolveInfo);
+ return new QueryIntentActivitiesResult(
+ applyPostResolutionFilter(result, instantAppPkgName,
+ allowDynamicSplits, filterCallingUid, resolveForStart,
+ userId, intent));
+ } else if (result.size() <= 1 && prioritizedXpInfo == null) {
+ // No result in parent user and <= 1 result in current profile, and we
+ // are not going to add ephemeral app, so we can return the result
+ // without further processing.
return new QueryIntentActivitiesResult(
applyPostResolutionFilter(result, instantAppPkgName,
allowDynamicSplits, filterCallingUid, resolveForStart,
userId, intent));
}
- } else if (result.size() <= 1 && !addInstant) {
- // No result in parent user and <= 1 result in current profile, and we
- // are not going to add ephemeral app, so we can return the result without
- // further processing.
- return new QueryIntentActivitiesResult(
- applyPostResolutionFilter(result, instantAppPkgName,
- allowDynamicSplits, filterCallingUid, resolveForStart, userId,
- intent));
}
+
// We have more than one candidate (combining results from current and parent
// profile), so we need filtering and sorting.
result = filterCandidatesWithDomainPreferredActivitiesLPr(
- intent, flags, result, xpDomainInfo, userId);
+ intent, flags, result, prioritizedXpInfo, userId);
sortResult = true;
+ } else {
+ // If not web Intent, just add result to candidate set and let ResolverActivity
+ // figure it out.
+ if (specificXpInfo != null) {
+ result.add(specificXpInfo.resolveInfo);
+ sortResult = true;
+ }
}
} else {
final PackageSetting setting =
@@ -2833,15 +2834,17 @@ public class PackageManagerService extends IPackageManager.Stub
if (ps == null) {
continue;
}
+
+ int approvalLevel = mDomainVerificationManager
+ .approvalLevelForDomain(ps, intent, flags, parentUserId);
+
if (result == null) {
- result = new CrossProfileDomainInfo();
- result.resolveInfo = createForwardingResolveInfoUnchecked(
- new WatchedIntentFilter(), sourceUserId, parentUserId);
+ result = new CrossProfileDomainInfo(createForwardingResolveInfoUnchecked(
+ new WatchedIntentFilter(), sourceUserId, parentUserId), approvalLevel);
+ } else {
+ result.highestApprovalLevel =
+ Math.max(approvalLevel, result.highestApprovalLevel);
}
-
- result.highestApprovalLevel = Math.max(mDomainVerificationManager
- .approvalLevelForDomain(ps, intent, resultTargetUser, flags,
- parentUserId), result.highestApprovalLevel);
}
if (result != null && result.highestApprovalLevel
<= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
@@ -3088,8 +3091,8 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageName = info.activityInfo.packageName;
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps.getInstantApp(userId)) {
- if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
- instantApps, flags, userId)) {
+ if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags,
+ userId)) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "Instant app approved for intent; pkg: "
+ packageName);
@@ -3416,28 +3419,59 @@ public class PackageManagerService extends IPackageManager.Stub
}
/**
- * If the filter's target user can handle the intent and is enabled: returns a ResolveInfo
- * that
- * will forward the intent to the filter's target user.
- * Otherwise, returns null.
+ * If the filter's target user can handle the intent and is enabled: a [ResolveInfo] that
+ * will forward the intent to the filter's target user, along with the highest approval of
+ * any handler in the target user. Otherwise, returns null.
*/
- private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter,
- Intent intent,
- String resolvedType, int flags, int sourceUserId) {
+ @Nullable
+ private CrossProfileDomainInfo createForwardingResolveInfo(
+ @NonNull CrossProfileIntentFilter filter, @NonNull Intent intent,
+ @Nullable String resolvedType, int flags, int sourceUserId) {
int targetUserId = filter.getTargetUserId();
+ if (!isUserEnabled(targetUserId)) {
+ return null;
+ }
+
List<ResolveInfo> resultTargetUser = mComponentResolver.queryActivities(intent,
resolvedType, flags, targetUserId);
- if (resultTargetUser != null && isUserEnabled(targetUserId)) {
+ if (CollectionUtils.isEmpty(resultTargetUser)) {
+ return null;
+ }
+
+ ResolveInfo forwardingInfo = null;
+ for (int i = resultTargetUser.size() - 1; i >= 0; i--) {
+ ResolveInfo targetUserResolveInfo = resultTargetUser.get(i);
+ if ((targetUserResolveInfo.activityInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_SUSPENDED) == 0) {
+ forwardingInfo = createForwardingResolveInfoUnchecked(filter, sourceUserId,
+ targetUserId);
+ break;
+ }
+ }
+
+ if (forwardingInfo == null) {
// If all the matches in the target profile are suspended, return null.
- for (int i = resultTargetUser.size() - 1; i >= 0; i--) {
- if ((resultTargetUser.get(i).activityInfo.applicationInfo.flags
- & ApplicationInfo.FLAG_SUSPENDED) == 0) {
- return createForwardingResolveInfoUnchecked(filter,
- sourceUserId, targetUserId);
- }
+ return null;
+ }
+
+ int highestApprovalLevel = DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
+
+ int size = resultTargetUser.size();
+ for (int i = 0; i < size; i++) {
+ ResolveInfo riTargetUser = resultTargetUser.get(i);
+ if (riTargetUser.handleAllWebDataURI) {
+ continue;
}
+ String packageName = riTargetUser.activityInfo.packageName;
+ PackageSetting ps = mSettings.getPackageLPr(packageName);
+ if (ps == null) {
+ continue;
+ }
+ highestApprovalLevel = Math.max(highestApprovalLevel, mDomainVerificationManager
+ .approvalLevelForDomain(ps, intent, flags, targetUserId));
}
- return null;
+
+ return new CrossProfileDomainInfo(forwardingInfo, highestApprovalLevel);
}
public ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
@@ -3476,34 +3510,59 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Return matching ResolveInfo in target user if any.
- private ResolveInfo queryCrossProfileIntents(
+ @Nullable
+ private CrossProfileDomainInfo queryCrossProfileIntents(
List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
int flags, int sourceUserId, boolean matchInCurrentProfile) {
- if (matchingFilters != null) {
- // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
- // match the same intent. For performance reasons, it is better not to
- // run queryIntent twice for the same userId
- SparseBooleanArray alreadyTriedUserIds = new SparseBooleanArray();
- int size = matchingFilters.size();
- for (int i = 0; i < size; i++) {
- CrossProfileIntentFilter filter = matchingFilters.get(i);
- int targetUserId = filter.getTargetUserId();
- boolean skipCurrentProfile =
- (filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0;
- boolean skipCurrentProfileIfNoMatchFound =
- (filter.getFlags() & PackageManager.ONLY_IF_NO_MATCH_FOUND) != 0;
- if (!skipCurrentProfile && !alreadyTriedUserIds.get(targetUserId)
- && (!skipCurrentProfileIfNoMatchFound || !matchInCurrentProfile)) {
- // Checking if there are activities in the target user that can handle the
- // intent.
- ResolveInfo resolveInfo = createForwardingResolveInfo(filter, intent,
- resolvedType, flags, sourceUserId);
- if (resolveInfo != null) return resolveInfo;
- alreadyTriedUserIds.put(targetUserId, true);
+ if (matchingFilters == null) {
+ return null;
+ }
+ // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
+ // match the same intent. For performance reasons, it is better not to
+ // run queryIntent twice for the same userId
+ SparseBooleanArray alreadyTriedUserIds = new SparseBooleanArray();
+
+ CrossProfileDomainInfo resultInfo = null;
+
+ int size = matchingFilters.size();
+ for (int i = 0; i < size; i++) {
+ CrossProfileIntentFilter filter = matchingFilters.get(i);
+ int targetUserId = filter.getTargetUserId();
+ boolean skipCurrentProfile =
+ (filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0;
+ boolean skipCurrentProfileIfNoMatchFound =
+ (filter.getFlags() & PackageManager.ONLY_IF_NO_MATCH_FOUND) != 0;
+ if (!skipCurrentProfile && !alreadyTriedUserIds.get(targetUserId)
+ && (!skipCurrentProfileIfNoMatchFound || !matchInCurrentProfile)) {
+ // Checking if there are activities in the target user that can handle the
+ // intent.
+ CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent,
+ resolvedType, flags, sourceUserId);
+ if (info != null) {
+ resultInfo = info;
+ break;
}
+ alreadyTriedUserIds.put(targetUserId, true);
}
}
- return null;
+
+ if (resultInfo == null) {
+ return null;
+ }
+
+ ResolveInfo forwardingResolveInfo = resultInfo.resolveInfo;
+ if (!isUserEnabled(forwardingResolveInfo.targetUserId)) {
+ return null;
+ }
+
+ List<ResolveInfo> filteredResult =
+ filterIfNotSystemUser(Collections.singletonList(forwardingResolveInfo),
+ sourceUserId);
+ if (filteredResult.isEmpty()) {
+ return null;
+ }
+
+ return resultInfo;
}
private ResolveInfo querySkipCurrentProfileIntents(
@@ -3516,10 +3575,10 @@ public class PackageManagerService extends IPackageManager.Stub
if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0) {
// Checking if there are activities in the target user that can handle the
// intent.
- ResolveInfo resolveInfo = createForwardingResolveInfo(filter, intent,
+ CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent,
resolvedType, flags, sourceUserId);
- if (resolveInfo != null) {
- return resolveInfo;
+ if (info != null) {
+ return info.resolveInfo;
}
}
}
@@ -4029,8 +4088,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (ps != null) {
// only check domain verification status if the app is not a browser
if (!info.handleAllWebDataURI) {
- if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
- resolvedActivities, flags, userId)) {
+ if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags,
+ userId)) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "DENY instant app;" + " pkg: " + packageName
+ ", approved");
@@ -8167,7 +8226,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (best == null || cur.priority > best.priority) {
- if (cur.getComponentInfo().enabled) {
+ if (isComponentEffectivelyEnabled(cur.getComponentInfo(), UserHandle.USER_SYSTEM)) {
best = cur;
} else {
Slog.w(TAG, "Domain verification agent found but not enabled");
@@ -9497,21 +9556,19 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isProtectedBroadcast(String actionName) {
- // allow instant applications
- synchronized (mProtectedBroadcasts) {
- if (mProtectedBroadcasts.contains(actionName)) {
+ if (actionName != null) {
+ // TODO: remove these terrible hacks
+ if (actionName.startsWith("android.net.netmon.lingerExpired")
+ || actionName.startsWith("com.android.server.sip.SipWakeupTimer")
+ || actionName.startsWith("com.android.internal.telephony.data-reconnect")
+ || actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) {
return true;
- } else if (actionName != null) {
- // TODO: remove these terrible hacks
- if (actionName.startsWith("android.net.netmon.lingerExpired")
- || actionName.startsWith("com.android.server.sip.SipWakeupTimer")
- || actionName.startsWith("com.android.internal.telephony.data-reconnect")
- || actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) {
- return true;
- }
}
}
- return false;
+ // allow instant applications
+ synchronized (mProtectedBroadcasts) {
+ return mProtectedBroadcasts.contains(actionName);
+ }
}
@Override
@@ -10131,7 +10188,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageName = ri.activityInfo.packageName;
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && hasAnyDomainApproval(mDomainVerificationManager, ps,
- intent, query, flags, userId)) {
+ intent, flags, userId)) {
return ri;
}
}
@@ -10188,10 +10245,10 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private static boolean hasAnyDomainApproval(
@NonNull DomainVerificationManagerInternal manager, @NonNull PackageSetting pkgSetting,
- @NonNull Intent intent, @NonNull List<ResolveInfo> candidates,
- @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
- return manager.approvalLevelForDomain(pkgSetting, intent, candidates, resolveInfoFlags,
- userId) > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
+ @NonNull Intent intent, @PackageManager.ResolveInfoFlags int resolveInfoFlags,
+ @UserIdInt int userId) {
+ return manager.approvalLevelForDomain(pkgSetting, intent, resolveInfoFlags, userId)
+ > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
}
/**
@@ -10624,7 +10681,20 @@ public class PackageManagerService extends IPackageManager.Stub
private static class CrossProfileDomainInfo {
/* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
ResolveInfo resolveInfo;
- int highestApprovalLevel = DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
+ int highestApprovalLevel;
+
+ CrossProfileDomainInfo(ResolveInfo resolveInfo, int highestApprovalLevel) {
+ this.resolveInfo = resolveInfo;
+ this.highestApprovalLevel = highestApprovalLevel;
+ }
+
+ @Override
+ public String toString() {
+ return "CrossProfileDomainInfo{"
+ + "resolveInfo=" + resolveInfo
+ + ", highestApprovalLevel=" + highestApprovalLevel
+ + '}';
+ }
}
private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
@@ -15143,9 +15213,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r);
}
- if (!pkg.getProtectedBroadcasts().isEmpty()) {
+ final List<String> protectedBroadcasts = pkg.getProtectedBroadcasts();
+ if (!protectedBroadcasts.isEmpty()) {
synchronized (mProtectedBroadcasts) {
- mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts());
+ mProtectedBroadcasts.addAll(protectedBroadcasts);
}
}
@@ -16915,6 +16986,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void setInstallerPackageName(String targetPackage, String installerPackageName) {
final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
if (getInstantAppPackageName(callingUid) != null) {
return;
}
@@ -16923,14 +16995,16 @@ public class PackageManagerService extends IPackageManager.Stub
PackageSetting targetPackageSetting = mSettings.getPackageLPr(targetPackage);
if (targetPackageSetting == null
|| shouldFilterApplicationLocked(
- targetPackageSetting, callingUid, UserHandle.getUserId(callingUid))) {
+ targetPackageSetting, callingUid, callingUserId)) {
throw new IllegalArgumentException("Unknown target package: " + targetPackage);
}
PackageSetting installerPackageSetting;
if (installerPackageName != null) {
installerPackageSetting = mSettings.getPackageLPr(installerPackageName);
- if (installerPackageSetting == null) {
+ if (installerPackageSetting == null
+ || shouldFilterApplicationLocked(
+ installerPackageSetting, callingUid, callingUserId)) {
throw new IllegalArgumentException("Unknown installer package: "
+ installerPackageName);
}
@@ -17118,7 +17192,7 @@ public class PackageManagerService extends IPackageManager.Stub
try {
// Should directory scanning logic be moved to ApexManager for better test coverage?
final File dir = request.args.origin.resolvedFile;
- final String[] apexes = dir.list();
+ final File[] apexes = dir.listFiles();
if (apexes == null) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
dir.getAbsolutePath() + " is not a directory");
@@ -17128,7 +17202,9 @@ public class PackageManagerService extends IPackageManager.Stub
"Expected exactly one .apex file under " + dir.getAbsolutePath()
+ " got: " + apexes.length);
}
- mApexManager.installPackage(dir.getAbsolutePath() + "/" + apexes[0]);
+ try (PackageParser2 packageParser = mInjector.getScanningPackageParser()) {
+ mApexManager.installPackage(apexes[0], packageParser);
+ }
} catch (PackageManagerException e) {
request.installResult.setError("APEX installation failed", e);
}
@@ -24111,6 +24187,42 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ /**
+ * @return true if the runtime app user enabled state, runtime component user enabled state,
+ * install-time app manifest enabled state, and install-time component manifest enabled state
+ * are all effectively enabled for the given component. Or if the component cannot be found,
+ * returns false.
+ */
+ private boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
+ @UserIdInt int userId) {
+ synchronized (mLock) {
+ try {
+ String packageName = componentInfo.packageName;
+ int appEnabledSetting =
+ mSettings.getApplicationEnabledSettingLPr(packageName, userId);
+ if (appEnabledSetting == COMPONENT_ENABLED_STATE_DEFAULT) {
+ if (!componentInfo.applicationInfo.enabled) {
+ return false;
+ }
+ } else if (appEnabledSetting != COMPONENT_ENABLED_STATE_ENABLED) {
+ return false;
+ }
+
+ int componentEnabledSetting = mSettings.getComponentEnabledSettingLPr(
+ componentInfo.getComponentName(), userId);
+ if (componentEnabledSetting == COMPONENT_ENABLED_STATE_DEFAULT) {
+ return componentInfo.isEnabled();
+ } else if (componentEnabledSetting != COMPONENT_ENABLED_STATE_ENABLED) {
+ return false;
+ }
+
+ return true;
+ } catch (PackageManager.NameNotFoundException ignored) {
+ return false;
+ }
+ }
+ }
+
@Override
public void enterSafeMode() {
enforceSystemOrRoot("Only the system can request entering safe mode");
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 4ebf4768a973..f9c63a948a86 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -3772,9 +3772,6 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" get-oem-permissions TARGET-PACKAGE");
pw.println(" Prints all OEM permissions for a package.");
pw.println("");
- pw.println(" set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}");
- pw.println(" get-app-link [--user USER_ID] PACKAGE");
- pw.println("");
pw.println(" trim-caches DESIRED_FREE_SPACE [internal|UUID]");
pw.println(" Trim cache files to reach the given free space.");
pw.println("");
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index 65e4e95759b8..262734fe18b4 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -389,7 +389,6 @@ public interface DomainVerificationManagerInternal {
*/
@ApprovalLevel
int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
- @NonNull List<ResolveInfo> candidates,
@PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId);
/**
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index b1b4e2afeb49..ba64d25178e7 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -1717,7 +1717,6 @@ public class DomainVerificationService extends SystemService
@Override
public int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
- @NonNull List<ResolveInfo> candidates,
@PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
String packageName = pkgSetting.getName();
if (!DomainVerificationUtils.isDomainVerificationIntent(intent, resolveInfoFlags)) {
@@ -1783,9 +1782,26 @@ public class DomainVerificationService extends SystemService
return APPROVAL_LEVEL_NONE;
}
- if (!pkgUserState.installed || !pkgUserState.isPackageEnabled(pkg)) {
+ if (!pkgUserState.installed) {
if (DEBUG_APPROVAL) {
- debugApproval(packageName, debugObject, userId, false, "package not enabled");
+ debugApproval(packageName, debugObject, userId, false,
+ "package not installed for user");
+ }
+ return APPROVAL_LEVEL_NONE;
+ }
+
+ if (!pkgUserState.isPackageEnabled(pkg)) {
+ if (DEBUG_APPROVAL) {
+ debugApproval(packageName, debugObject, userId, false,
+ "package not enabled for user");
+ }
+ return APPROVAL_LEVEL_NONE;
+ }
+
+ if (pkgUserState.suspended) {
+ if (DEBUG_APPROVAL) {
+ debugApproval(packageName, debugObject, userId, false,
+ "package suspended for user");
}
return APPROVAL_LEVEL_NONE;
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING b/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
index 5fcf4118ddd1..ba4a62cdbbf1 100644
--- a/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
@@ -9,7 +9,10 @@
]
},
{
- "name": "CtsDomainVerificationDeviceTestCases"
+ "name": "CtsDomainVerificationDeviceStandaloneTestCases"
+ },
+ {
+ "name": "CtsDomainVerificationDeviceMultiUserTestCases"
},
{
"name": "CtsDomainVerificationHostTestCases"
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
index bf54bd527f57..9b0ef15c8bd6 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
@@ -67,7 +67,8 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
* <ul>
* <li> The matrix does not automatically shrink but there is a compress() method that
* will recover unused space.
- * <li> Equality is a very, very expesive operation.
+ * <li> Equality is a very, very expensive operation because it must walk the matrices
+ * beimg compared element by element.
* </ul>
*/
@@ -79,10 +80,9 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
static final int STEP = 64;
/**
- * There are 8 bits in a byte. The constant is defined here only to make it easy to
- * find in the code.
+ * The number of bits in the mValues array element.
*/
- private static final int BYTE = 8;
+ private static final int PACKING = 32;
/**
* Constants that index into the string array returned by matrixToString. The primary
@@ -123,7 +123,7 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
/**
* The boolean array. This array is always {@code mOrder x mOrder} in size.
*/
- private byte[] mValues;
+ private int[] mValues;
/**
* A convenience function called when the elements are added to or removed from the storage.
@@ -157,10 +157,10 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
throw new RuntimeException("mOrder is " + mOrder + " initCap is " + initialCapacity);
}
- mInUse = new boolean[mOrder];
+ mInUse = ArrayUtils.newUnpaddedBooleanArray(mOrder);
mKeys = ArrayUtils.newUnpaddedIntArray(mOrder);
mMap = ArrayUtils.newUnpaddedIntArray(mOrder);
- mValues = new byte[mOrder * mOrder / 8];
+ mValues = ArrayUtils.newUnpaddedIntArray(mOrder * mOrder / PACKING);
mSize = 0;
}
@@ -301,8 +301,8 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
*/
private boolean valueAtInternal(int row, int col) {
int element = row * mOrder + col;
- int offset = element / BYTE;
- int mask = 1 << (element % BYTE);
+ int offset = element / PACKING;
+ int mask = 1 << (element % PACKING);
return (mValues[offset] & mask) != 0;
}
@@ -324,8 +324,8 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
*/
private void setValueAtInternal(int row, int col, boolean value) {
int element = row * mOrder + col;
- int offset = element / BYTE;
- byte mask = (byte) (1 << (element % BYTE));
+ int offset = element / PACKING;
+ int mask = 1 << (element % PACKING);
if (value) {
mValues[offset] |= mask;
} else {
@@ -377,10 +377,10 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
mSize++;
// Initialize the row and column corresponding to the new index.
- int valueRow = mOrder / BYTE;
- int offset = newIndex / BYTE;
- byte mask = (byte) (~(1 << (newIndex % BYTE)));
- Arrays.fill(mValues, newIndex * valueRow, (newIndex + 1) * valueRow, (byte) 0);
+ int valueRow = mOrder / PACKING;
+ int offset = newIndex / PACKING;
+ int mask = ~(1 << (newIndex % PACKING));
+ Arrays.fill(mValues, newIndex * valueRow, (newIndex + 1) * valueRow, 0);
for (int n = 0; n < mSize; n++) {
mValues[n * valueRow + offset] &= mask;
}
@@ -412,25 +412,36 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
* Expand the 2D array. This also extends the free list.
*/
private void growMatrix() {
- resizeValues(mOrder + STEP);
+ resizeMatrix(mOrder + STEP);
}
/**
* Resize the values array to the new dimension.
*/
- private void resizeValues(int newOrder) {
-
- boolean[] newInuse = Arrays.copyOf(mInUse, newOrder);
+ private void resizeMatrix(int newOrder) {
+ if (newOrder % STEP != 0) {
+ throw new IllegalArgumentException("matrix order " + newOrder
+ + " is not a multiple of " + STEP);
+ }
int minOrder = Math.min(mOrder, newOrder);
- byte[] newValues = new byte[newOrder * newOrder / BYTE];
+ boolean[] newInUse = ArrayUtils.newUnpaddedBooleanArray(newOrder);
+ System.arraycopy(mInUse, 0, newInUse, 0, minOrder);
+ int[] newMap = ArrayUtils.newUnpaddedIntArray(newOrder);
+ System.arraycopy(mMap, 0, newMap, 0, minOrder);
+ int[] newKeys = ArrayUtils.newUnpaddedIntArray(newOrder);
+ System.arraycopy(mKeys, 0, newKeys, 0, minOrder);
+
+ int[] newValues = ArrayUtils.newUnpaddedIntArray(newOrder * newOrder / PACKING);
for (int i = 0; i < minOrder; i++) {
- int row = mOrder * i / BYTE;
- int newRow = newOrder * i / BYTE;
- System.arraycopy(mValues, row, newValues, newRow, minOrder / BYTE);
+ int row = mOrder * i / PACKING;
+ int newRow = newOrder * i / PACKING;
+ System.arraycopy(mValues, row, newValues, newRow, minOrder / PACKING);
}
- mInUse = newInuse;
+ mInUse = newInUse;
+ mMap = newMap;
+ mKeys = newKeys;
mValues = newValues;
mOrder = newOrder;
}
@@ -482,21 +493,21 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
int src = mMap[srcIndex];
mInUse[src] = false;
mMap[srcIndex] = dst;
- System.arraycopy(mValues, src * mOrder / BYTE,
- mValues, dst * mOrder / BYTE,
- mOrder / BYTE);
- int srcOffset = (src / BYTE);
- byte srcMask = (byte) (1 << (src % BYTE));
- int dstOffset = (dst / BYTE);
- byte dstMask = (byte) (1 << (dst % BYTE));
+ System.arraycopy(mValues, src * mOrder / PACKING,
+ mValues, dst * mOrder / PACKING,
+ mOrder / PACKING);
+ int srcOffset = (src / PACKING);
+ int srcMask = 1 << (src % PACKING);
+ int dstOffset = (dst / PACKING);
+ int dstMask = 1 << (dst % PACKING);
for (int i = 0; i < mOrder; i++) {
if ((mValues[srcOffset] & srcMask) == 0) {
mValues[dstOffset] &= ~dstMask;
} else {
mValues[dstOffset] |= dstMask;
}
- srcOffset += mOrder / BYTE;
- dstOffset += mOrder / BYTE;
+ srcOffset += mOrder / PACKING;
+ dstOffset += mOrder / PACKING;
}
}
}
@@ -508,7 +519,7 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
pack();
int unused = (mOrder - mSize) / STEP;
if (unused > 0) {
- resizeValues(mOrder - (unused * STEP));
+ resizeMatrix(mOrder - (unused * STEP));
}
}
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index 732035951462..ee7bf5f0d958 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -122,7 +122,6 @@ public class UnderlyingNetworkTracker {
@NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup;
- @NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities;
@NonNull private final UnderlyingNetworkTrackerCallback mCb;
@NonNull private final Dependencies mDeps;
@NonNull private final Handler mHandler;
@@ -147,13 +146,11 @@ public class UnderlyingNetworkTracker {
@NonNull VcnContext vcnContext,
@NonNull ParcelUuid subscriptionGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
- @NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
@NonNull UnderlyingNetworkTrackerCallback cb) {
this(
vcnContext,
subscriptionGroup,
snapshot,
- requiredUnderlyingNetworkCapabilities,
cb,
new Dependencies());
}
@@ -162,16 +159,11 @@ public class UnderlyingNetworkTracker {
@NonNull VcnContext vcnContext,
@NonNull ParcelUuid subscriptionGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
- @NonNull Set<Integer> requiredUnderlyingNetworkCapabilities,
@NonNull UnderlyingNetworkTrackerCallback cb,
@NonNull Dependencies deps) {
mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
- mRequiredUnderlyingNetworkCapabilities =
- Objects.requireNonNull(
- requiredUnderlyingNetworkCapabilities,
- "Missing requiredUnderlyingNetworkCapabilities");
mCb = Objects.requireNonNull(cb, "Missing cb");
mDeps = Objects.requireNonNull(deps, "Missing deps");
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 55e3ed620160..493697049f34 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -674,7 +674,6 @@ public class VcnGatewayConnection extends StateMachine {
mVcnContext,
subscriptionGroup,
mLastSnapshot,
- mConnectionConfig.getAllUnderlyingCapabilities(),
mUnderlyingNetworkTrackerCallback);
mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class);
@@ -2295,13 +2294,11 @@ public class VcnGatewayConnection extends StateMachine {
VcnContext vcnContext,
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
- Set<Integer> requiredUnderlyingNetworkCapabilities,
UnderlyingNetworkTrackerCallback callback) {
return new UnderlyingNetworkTracker(
vcnContext,
subscriptionGroup,
snapshot,
- requiredUnderlyingNetworkCapabilities,
callback);
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 53f1035ee422..c888e545b24e 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -628,7 +628,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
// scale if the crop height winds up not matching the recommended metrics
- needScale = cropHint.height() > wpData.mHeight
+ needScale = wpData.mHeight != cropHint.height()
|| cropHint.height() > GLHelper.getMaxTextureSize()
|| cropHint.width() > GLHelper.getMaxTextureSize();
@@ -752,7 +752,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
f = new FileOutputStream(wallpaper.cropFile);
bos = new BufferedOutputStream(f, 32*1024);
- finalCrop.compress(Bitmap.CompressFormat.PNG, 100, bos);
+ finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush(); // don't rely on the implicit flush-at-close when noting success
success = true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index a781520c48d9..2b6a83896cc6 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -102,7 +102,6 @@ import com.android.server.apphibernation.AppHibernationManagerInternal;
import com.android.server.apphibernation.AppHibernationService;
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
/**
@@ -216,7 +215,7 @@ class ActivityMetricsLogger {
/** whether the process of the launching activity didn't have any active activity. */
final boolean mProcessSwitch;
/** The activities that should be drawn. */
- final LinkedList<ActivityRecord> mPendingDrawActivities = new LinkedList<>();
+ final ArrayList<ActivityRecord> mPendingDrawActivities = new ArrayList<>(2);
/** The latest activity to have been launched. */
@NonNull ActivityRecord mLastLaunchedActivity;
@@ -328,6 +327,17 @@ class ActivityMetricsLogger {
return mPendingDrawActivities.isEmpty();
}
+ /** Only keep the records which can be drawn. */
+ void updatePendingDraw() {
+ for (int i = mPendingDrawActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = mPendingDrawActivities.get(i);
+ if (!r.mVisibleRequested) {
+ if (DEBUG_METRICS) Slog.i(TAG, "Discard pending draw " + r);
+ mPendingDrawActivities.remove(i);
+ }
+ }
+ }
+
/**
* @return {@code true} if the transition info should be sent to MetricsLogger, StatsLog, or
* LaunchObserver.
@@ -701,6 +711,7 @@ class ActivityMetricsLogger {
info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs);
info.mReason = activityToReason.valueAt(index);
info.mLoggedTransitionStarting = true;
+ info.updatePendingDraw();
if (info.allDrawn()) {
done(false /* abort */, info, "notifyTransitionStarting - all windows drawn",
timestampNs);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 5635c33995b1..95e5fc2e6b27 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -340,7 +340,7 @@ class WallpaperController {
rawChanged = true;
}
- boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset,
+ boolean changed = wallpaperWin.setWallpaperOffset(xOffset, yOffset,
wallpaperWin.mShouldScaleWallpaper
? zoomOutToScale(wallpaperWin.mWallpaperZoomOut) : 1);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b28297ed4af8..642ce1b34769 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -445,6 +445,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
float mOverrideScale = 1;
float mHScale=1, mVScale=1;
float mLastHScale=1, mLastVScale=1;
+
+ // An offset in pixel of the surface contents from the window position. Used for Wallpaper
+ // to provide the effect of scrolling within a large surface. We just use these values as
+ // a cache.
+ int mXOffset = 0;
+ int mYOffset = 0;
+
+ // A scale factor for the surface contents, that will be applied from the center of the visible
+ // region.
+ float mWallpaperScale = 1f;
+
final Matrix mTmpMatrix = new Matrix();
final float[] mTmpMatrixArray = new float[9];
@@ -5443,10 +5454,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
private void updateScaleIfNeeded() {
- if (mLastGlobalScale != mGlobalScale || mLastHScale != mHScale ||
- mLastVScale != mVScale ) {
+ float newHScale = mHScale * mGlobalScale * mWallpaperScale;
+ float newVScale = mVScale * mGlobalScale * mWallpaperScale;
+ if (mLastHScale != newHScale ||
+ mLastVScale != newVScale ) {
getPendingTransaction().setMatrix(getSurfaceControl(),
- mGlobalScale*mHScale, 0, 0, mGlobalScale*mVScale);
+ newHScale, 0, 0, newVScale);
mLastGlobalScale = mGlobalScale;
mLastHScale = mHScale;
mLastVScale = mVScale;
@@ -5484,6 +5497,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mSurfacePlacementNeeded = false;
transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,
mSurfacePosition);
+ mSurfacePosition.offset(mXOffset, mYOffset);
// Freeze position while we're unrotated, so the surface remains at the position it was
// prior to the rotation.
@@ -6096,4 +6110,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void markRedrawForSyncReported() {
mRedrawForSyncReported = true;
}
+
+ boolean setWallpaperOffset(int dx, int dy, float scale) {
+ if (mXOffset == dx && mYOffset == dy && Float.compare(mWallpaperScale, scale) == 0) {
+ return false;
+ }
+ mXOffset = dx;
+ mYOffset = dy;
+ mWallpaperScale = scale;
+ scheduleAnimation();
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ea3b0658c4d5..9a6e4448966d 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -169,16 +169,6 @@ class WindowStateAnimator {
int mAttrType;
- // An offset in pixel of the surface contents from the window position. Used for Wallpaper
- // to provide the effect of scrolling within a large surface. We just use these values as
- // a cache.
- int mXOffset = 0;
- int mYOffset = 0;
-
- // A scale factor for the surface contents, that will be applied from the center of the visible
- // region.
- float mWallpaperScale = 1f;
-
private final Rect mTmpSize = new Rect();
/**
@@ -502,18 +492,6 @@ class WindowStateAnimator {
}
final WindowState w = mWin;
-
- if (!w.mSeamlesslyRotated) {
- // Used to offset the WSA when stack position changes before a resize.
- int xOffset = mXOffset;
- int yOffset = mYOffset;
- if (!mIsWallpaper) {
- mSurfaceController.setPosition(t, xOffset, yOffset);
- } else {
- setWallpaperPositionAndScale(t, xOffset, yOffset, mWallpaperScale);
- }
- }
-
final Task task = w.getTask();
if (shouldConsumeMainWindowSizeTransaction()) {
if (isInBlastSync()) {
@@ -575,14 +553,8 @@ class WindowStateAnimator {
"SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s",
mSurfaceController, mShownAlpha, w.mHScale, w.mVScale, w);
- boolean prepared = true;
-
- if (mIsWallpaper) {
- setWallpaperPositionAndScale(t, mXOffset, mYOffset, mWallpaperScale);
- } else {
- prepared =
- mSurfaceController.prepareToShowInTransaction(t, mShownAlpha);
- }
+ boolean prepared =
+ mSurfaceController.prepareToShowInTransaction(t, mShownAlpha);
if (prepared && mDrawState == HAS_DRAWN) {
if (mLastHidden) {
@@ -635,53 +607,6 @@ class WindowStateAnimator {
}
}
- boolean setWallpaperOffset(int dx, int dy, float scale) {
- if (mXOffset == dx && mYOffset == dy && Float.compare(mWallpaperScale, scale) == 0) {
- return false;
- }
- mXOffset = dx;
- mYOffset = dy;
- mWallpaperScale = scale;
-
- if (mSurfaceController != null) {
- try {
- if (SHOW_LIGHT_TRANSACTIONS) {
- Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
- }
- mService.openSurfaceTransaction();
- setWallpaperPositionAndScale(SurfaceControl.getGlobalTransaction(), dx, dy, scale);
- } catch (RuntimeException e) {
- Slog.w(TAG, "Error positioning surface of " + mWin
- + " pos=(" + dx + "," + dy + ")", e);
- } finally {
- mService.closeSurfaceTransaction("setWallpaperOffset");
- if (SHOW_LIGHT_TRANSACTIONS) {
- Slog.i(TAG, "<<< CLOSE TRANSACTION setWallpaperOffset");
- }
- }
- }
-
- return true;
- }
-
- private void setWallpaperPositionAndScale(SurfaceControl.Transaction t, int dx, int dy,
- float scale) {
- DisplayInfo displayInfo = mWin.getDisplayInfo();
- Matrix matrix = mWin.mTmpMatrix;
- matrix.setTranslate(dx, dy);
- matrix.postScale(scale, scale, displayInfo.logicalWidth / 2f,
- displayInfo.logicalHeight / 2f);
- matrix.getValues(mWin.mTmpMatrixArray);
- matrix.reset();
-
- mSurfaceController.setPosition(t,mWin.mTmpMatrixArray[MTRANS_X],
- mWin.mTmpMatrixArray[MTRANS_Y]);
- mSurfaceController.setMatrix(t, mWin.mTmpMatrixArray[MSCALE_X],
- mWin.mTmpMatrixArray[MSKEW_Y],
- mWin.mTmpMatrixArray[MSKEW_X],
- mWin.mTmpMatrixArray[MSCALE_Y]);
- }
-
/**
* Try to change the pixel format without recreating the surface. This
* will be common in the case of changing from PixelFormat.OPAQUE to
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 9d055e0d431f..339a5f916b4b 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -118,6 +118,11 @@ android_test {
":PackageParserTestApp3",
":PackageParserTestApp4",
":apex.test",
+ ":test.rebootless_apex_v1",
+ ":test.rebootless_apex_v2",
+ ":com.android.apex.cts.shim.v1_prebuilt",
+ ":com.android.apex.cts.shim.v2_different_certificate_prebuilt",
+ ":com.android.apex.cts.shim.v2_unsigned_apk_container_prebuilt",
],
resource_zips: [":FrameworksServicesTests_apks_as_resources"],
}
diff --git a/services/tests/servicestests/apks/install-split-base/AndroidManifest.xml b/services/tests/servicestests/apks/install-split-base/AndroidManifest.xml
index 1ff41e1d3328..ac563c6fef43 100644
--- a/services/tests/servicestests/apks/install-split-base/AndroidManifest.xml
+++ b/services/tests/servicestests/apks/install-split-base/AndroidManifest.xml
@@ -15,8 +15,11 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.servicestests.install_split"
- android:isolatedSplits="true">
+ package="com.android.frameworks.servicestests.install_split"
+ android:isolatedSplits="true"
+ android:versionCode="9001"
+ android:versionName="1.0"
+ >
<application android:label="ClassloaderSplitApp">
<activity android:name=".BaseActivity"
diff --git a/services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml b/services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml
index dfeec8c6bbd4..28c251cb914f 100644
--- a/services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml
+++ b/services/tests/servicestests/apks/install-split-feature-a/AndroidManifest.xml
@@ -15,8 +15,11 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.servicestests.install_split"
- featureSplit="feature_a">
+ package="com.android.frameworks.servicestests.install_split"
+ featureSplit="feature_a"
+ android:versionCode="9001"
+ android:versionName="1.0"
+ >
<application>
<activity android:name=".feature_a.FeatureAActivity"
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 9b25d0dc9c77..4e350b673b38 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
@@ -29,6 +30,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.expectThrows;
import android.apex.ApexInfo;
import android.apex.ApexSessionInfo;
@@ -84,7 +86,7 @@ public class ApexManagerTest {
@Test
public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
@@ -101,7 +103,7 @@ public class ApexManagerTest {
@Test
public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
@@ -118,7 +120,7 @@ public class ApexManagerTest {
@Test
public void testGetPackageInfo_setFlagsNone() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -127,7 +129,7 @@ public class ApexManagerTest {
@Test
public void testGetActivePackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -136,7 +138,7 @@ public class ApexManagerTest {
@Test
public void testGetActivePackages_noneActivePackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -145,7 +147,7 @@ public class ApexManagerTest {
@Test
public void testGetFactoryPackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -154,7 +156,7 @@ public class ApexManagerTest {
@Test
public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -163,7 +165,7 @@ public class ApexManagerTest {
@Test
public void testGetInactivePackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -172,7 +174,7 @@ public class ApexManagerTest {
@Test
public void testGetInactivePackages_noneInactivePackages() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -181,7 +183,7 @@ public class ApexManagerTest {
@Test
public void testIsApexPackage() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -276,11 +278,11 @@ public class ApexManagerTest {
@Test
public void testReportErrorWithApkInApex() throws RemoteException {
- when(mApexService.getActivePackages()).thenReturn(createApexInfo(true, true));
+ when(mApexService.getActivePackages()).thenReturn(createApexInfoForTestPkg(true, true));
final ApexManager.ActiveApexInfo activeApex = mApexManager.getActiveApexInfos().get(0);
assertThat(activeApex.apexModuleName).isEqualTo(TEST_APEX_PKG);
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -297,7 +299,7 @@ public class ApexManagerTest {
*/
@Test
public void testRegisterApkInApexDoesNotRegisterSimilarPrefix() throws RemoteException {
- when(mApexService.getActivePackages()).thenReturn(createApexInfo(true, true));
+ when(mApexService.getActivePackages()).thenReturn(createApexInfoForTestPkg(true, true));
final ApexManager.ActiveApexInfo activeApex = mApexManager.getActiveApexInfos().get(0);
assertThat(activeApex.apexModuleName).isEqualTo(TEST_APEX_PKG);
@@ -305,7 +307,7 @@ public class ApexManagerTest {
when(fakeApkInApex.getBaseApkPath()).thenReturn("/apex/" + TEST_APEX_PKG + "randomSuffix");
when(fakeApkInApex.getPackageName()).thenReturn("randomPackageName");
- when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true));
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -314,7 +316,112 @@ public class ApexManagerTest {
assertThat(mApexManager.getApksInApex(activeApex.apexModuleName)).isEmpty();
}
- private ApexInfo[] createApexInfo(boolean isActive, boolean isFactory) {
+ @Test
+ public void testInstallPackageFailsToInstallNewApex() throws Exception {
+ when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false));
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
+
+ File apex = extractResource("test.apex_rebootless_v1", "test.rebootless_apex_v1.apex");
+ PackageManagerException e = expectThrows(PackageManagerException.class,
+ () -> mApexManager.installPackage(apex, mPackageParser2));
+ assertThat(e).hasMessageThat().contains("It is forbidden to install new APEX packages");
+ }
+
+ @Test
+ public void testInstallPackageDowngrade() throws Exception {
+ File activeApex = extractResource("test.apex_rebootless_v2",
+ "test.rebootless_apex_v2.apex");
+ ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
+ /* isFactory= */ false, activeApex);
+ when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
+
+ File installedApex = extractResource("test.apex_rebootless_v1",
+ "test.rebootless_apex_v1.apex");
+ PackageManagerException e = expectThrows(PackageManagerException.class,
+ () -> mApexManager.installPackage(installedApex, mPackageParser2));
+ assertThat(e).hasMessageThat().contains(
+ "Downgrade of APEX package test.apex.rebootless is not allowed");
+ }
+
+ @Test
+ public void testInstallPackage() throws Exception {
+ ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
+ /* isFactory= */ false, extractResource("test.apex_rebootless_v1",
+ "test.rebootless_apex_v1.apex"));
+ when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
+
+ File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
+ ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
+ /* isFactory= */ false, finalApex);
+ when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo);
+
+ File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
+ mApexManager.installPackage(installedApex, mPackageParser2);
+
+ PackageInfo newInfo = mApexManager.getPackageInfo("test.apex.rebootless",
+ ApexManager.MATCH_ACTIVE_PACKAGE);
+ assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath());
+ assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2);
+ }
+
+ @Test
+ public void testInstallPackageBinderCallFails() throws Exception {
+ ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
+ /* isFactory= */ false, extractResource("test.apex_rebootless_v1",
+ "test.rebootless_apex_v1.apex"));
+ when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
+
+ when(mApexService.installAndActivatePackage(anyString())).thenThrow(
+ new RuntimeException("install failed :("));
+
+ File installedApex = extractResource("test.apex_rebootless_v1",
+ "test.rebootless_apex_v1.apex");
+ assertThrows(PackageManagerException.class,
+ () -> mApexManager.installPackage(installedApex, mPackageParser2));
+ }
+
+ @Test
+ public void testInstallPackageSignedWithWrongCertificate() throws Exception {
+ File activeApex = extractResource("shim_v1", "com.android.apex.cts.shim.apex");
+ ApexInfo activeApexInfo = createApexInfo("com.android.apex.cts.shim", 1,
+ /* isActive= */ true, /* isFactory= */ false, activeApex);
+ when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
+
+ File installedApex = extractResource("shim_different_certificate",
+ "com.android.apex.cts.shim.v2_different_certificate.apex");
+ PackageManagerException e = expectThrows(PackageManagerException.class,
+ () -> mApexManager.installPackage(installedApex, mPackageParser2));
+ assertThat(e).hasMessageThat().contains("APK container signature of ");
+ assertThat(e).hasMessageThat().contains(
+ "is not compatible with currently installed on device");
+ }
+
+ @Test
+ public void testInstallPackageUnsignedApexContainer() throws Exception {
+ File activeApex = extractResource("shim_v1", "com.android.apex.cts.shim.apex");
+ ApexInfo activeApexInfo = createApexInfo("com.android.apex.cts.shim", 1,
+ /* isActive= */ true, /* isFactory= */ false, activeApex);
+ when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
+ mApexManager.scanApexPackagesTraced(mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
+
+ File installedApex = extractResource("shim_unsigned_apk_container",
+ "com.android.apex.cts.shim.v2_unsigned_apk_container.apex");
+ PackageManagerException e = expectThrows(PackageManagerException.class,
+ () -> mApexManager.installPackage(installedApex, mPackageParser2));
+ assertThat(e).hasMessageThat().contains("Failed to collect certificates from ");
+ }
+
+ private ApexInfo[] createApexInfoForTestPkg(boolean isActive, boolean isFactory) {
File apexFile = extractResource(TEST_APEX_PKG, TEST_APEX_FILE_NAME);
ApexInfo apexInfo = new ApexInfo();
apexInfo.isActive = isActive;
@@ -327,6 +434,17 @@ public class ApexManagerTest {
return new ApexInfo[]{apexInfo};
}
+ private ApexInfo createApexInfo(String moduleName, int versionCode, boolean isActive,
+ boolean isFactory, File apexFile) {
+ ApexInfo apexInfo = new ApexInfo();
+ apexInfo.moduleName = moduleName;
+ apexInfo.versionCode = versionCode;
+ apexInfo.isActive = isActive;
+ apexInfo.isFactory = isFactory;
+ apexInfo.modulePath = apexFile.getPath();
+ return apexInfo;
+ }
+
private ApexSessionInfo getFakeStagedSessionInfo() {
ApexSessionInfo stagedSessionInfo = new ApexSessionInfo();
stagedSessionInfo.sessionId = TEST_SESSION_ID;
@@ -358,6 +476,7 @@ public class ApexManagerTest {
} catch (IOException e) {
throw new AssertionError("CreateTempFile IOException" + e);
}
+
try (
InputStream in = ApexManager.class.getClassLoader()
.getResourceAsStream(fullResourceName);
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index f9b8f26f1c86..bc0a54047ff1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -69,7 +69,7 @@ public class DexMetadataHelperTest {
private static final String DEX_METADATA_FILE_EXTENSION = ".dm";
private static final String DEX_METADATA_PACKAGE_NAME =
"com.android.frameworks.servicestests.install_split";
- private static long DEX_METADATA_VERSION_CODE = 30;
+ private static final long DEX_METADATA_VERSION_CODE = 9001;
@Rule
public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index beff3862df01..82c459c6868a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -353,8 +353,22 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
mTrampolineActivity.setVisibility(false);
notifyWindowsDrawn(mTopActivity);
- assertWithMessage("Trampoline activity is invisble so there should be no undrawn windows")
+ assertWithMessage("Trampoline activity is invisible so there should be no undrawn windows")
.that(mLaunchingState.allDrawn()).isTrue();
+
+ // Since the activity is drawn, the launch event should be reported.
+ notifyTransitionStarting(mTopActivity);
+ verifyOnActivityLaunchFinished(mTopActivity);
+ mLaunchTopByTrampoline = false;
+ clearInvocations(mLaunchObserver);
+
+ // Another round without setting visibility of the trampoline activity.
+ onActivityLaunchedTrampoline();
+ notifyWindowsDrawn(mTopActivity);
+ // If the transition can start, the invisible activities should be discarded and the launch
+ // event be reported successfully.
+ notifyTransitionStarting(mTopActivity);
+ verifyOnActivityLaunchFinished(mTopActivity);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 94297be0c121..5bc4c82f8d43 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1386,11 +1386,11 @@ public class DisplayContentTests extends WindowTestsBase {
performLayout(mDisplayContent);
// Force the negative offset to verify it can be updated.
- mWallpaperWindow.mWinAnimator.mXOffset = mWallpaperWindow.mWinAnimator.mYOffset = -1;
+ mWallpaperWindow.mXOffset = mWallpaperWindow.mYOffset = -1;
assertTrue(mDisplayContent.mWallpaperController.updateWallpaperOffset(mWallpaperWindow,
false /* sync */));
- assertThat(mWallpaperWindow.mWinAnimator.mXOffset).isGreaterThan(-1);
- assertThat(mWallpaperWindow.mWinAnimator.mYOffset).isGreaterThan(-1);
+ assertThat(mWallpaperWindow.mXOffset).isGreaterThan(-1);
+ assertThat(mWallpaperWindow.mYOffset).isGreaterThan(-1);
// The wallpaper need to animate with transformed position, so its surface position should
// not be reset.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index ada58a586ffc..3f0c13c83816 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -212,7 +212,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
// value did, and we do dispatch the zoom to the wallpaper service
dc.mWallpaperController.setWallpaperZoomOut(homeWindow, newZoom);
assertEquals(newZoom, wallpaperWindow.mWallpaperZoomOut, .01f);
- assertEquals(1f, wallpaperWindow.mWinAnimator.mWallpaperScale, .01f);
+ assertEquals(1f, wallpaperWindow.mWallpaperScale, .01f);
verify(wallpaperWindow.mClient).dispatchWallpaperOffsets(anyFloat(), anyFloat(), anyFloat(),
anyFloat(), eq(newZoom), anyBoolean());
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8fb805b543e2..c9996fb7141e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2680,8 +2680,8 @@ public class CarrierConfigManager {
/**
* List of EARFCN (E-UTRA Absolute Radio Frequency Channel Number,
- * Reference: 3GPP TS 36.104 5.4.3) inclusive ranges on which lte_rsrp_boost_int
- * will be applied. Format of the String array is expected to be {"erafcn1_start-earfcn1_end",
+ * Reference: 3GPP TS 36.104 5.4.3) inclusive ranges on which lte_earfcns_rsrp_boost_int
+ * will be applied. Format of the String array is expected to be {"earfcn1_start-earfcn1_end",
* "earfcn2_start-earfcn2_end" ... }
* @hide
*/
@@ -2689,6 +2689,24 @@ public class CarrierConfigManager {
"boosted_lte_earfcns_string_array";
/**
+ * Offset to be reduced from rsrp threshold while calculating signal strength level.
+ * @hide
+ */
+ public static final String KEY_NRARFCNS_RSRP_BOOST_INT_ARRAY = "nrarfcns_rsrp_boost_int_array";
+
+ /**
+ * List of NR ARFCN (5G Absolute Radio Frequency Channel Number,
+ * Reference: 3GPP TS 36.108) inclusive ranges on which corresponding
+ * nrarfcns_rsrp_boost_int_array will be applied. The size of this array and
+ * nrarfcns_rsrp_boost_int_array must be the same.
+ * Format of the String array is expected to be {"nrarfcn1_start-nrarfcn1_end",
+ * "nrarfcn2_start-nrarfcn2_end" ... }
+ * @hide
+ */
+ public static final String KEY_BOOSTED_NRARFCNS_STRING_ARRAY =
+ "boosted_nrarfcns_string_array";
+
+ /**
* Determine whether to use only RSRP for the number of LTE signal bars.
* @hide
*
@@ -5338,6 +5356,8 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_SUPPORT_IMS_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
+ sDefaults.putIntArray(KEY_NRARFCNS_RSRP_BOOST_INT_ARRAY, null);
+ sDefaults.putStringArray(KEY_BOOSTED_NRARFCNS_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
sDefaults.putInt(IMSI_KEY_AVAILABILITY_INT, 0);
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 7addf334e967..9211482fc067 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -314,7 +314,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
int rsrpBoost = 0;
if (ss != null) {
- rsrpBoost = ss.getLteEarfcnRsrpBoost();
+ rsrpBoost = ss.getArfcnRsrpBoost();
}
int rsrp = inRangeOrUnavailable(mRsrp + rsrpBoost, MIN_LTE_RSRP, MAX_LTE_RSRP);
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index ac01afa51729..72150ddf8597 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -419,7 +419,11 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
int ssRsrqLevel = SignalStrength.INVALID;
int ssSinrLevel = SignalStrength.INVALID;
if (isLevelForParameter(USE_SSRSRP)) {
- ssRsrpLevel = updateLevelWithMeasure(mSsRsrp, mSsRsrpThresholds);
+ int rsrpBoost = 0;
+ if (ss != null) {
+ rsrpBoost = ss.getArfcnRsrpBoost();
+ }
+ ssRsrpLevel = updateLevelWithMeasure(mSsRsrp + rsrpBoost, mSsRsrpThresholds);
if (VDBG) {
Rlog.i(TAG, "Updated 5G NR SSRSRP Level: " + ssRsrpLevel);
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 2d06062cfa44..6da61b712916 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -353,9 +353,11 @@ public class ServiceState implements Parcelable {
private int mChannelNumber;
private int[] mCellBandwidths = new int[0];
- /* EARFCN stands for E-UTRA Absolute Radio Frequency Channel Number,
- * Reference: 3GPP TS 36.104 5.4.3 */
- private int mLteEarfcnRsrpBoost = 0;
+ /**
+ * ARFCN stands for Absolute Radio Frequency Channel Number. This field is current used for
+ * LTE where it represents the boost for EARFCN (Reference: 3GPP TS 36.104 5.4.3) and for NR
+ * where it's for NR ARFCN (Reference: 3GPP TS 36.108) */
+ private int mArfcnRsrpBoost = 0;
private final List<NetworkRegistrationInfo> mNetworkRegistrationInfos = new ArrayList<>();
@@ -439,7 +441,7 @@ public class ServiceState implements Parcelable {
mChannelNumber = s.mChannelNumber;
mCellBandwidths = s.mCellBandwidths == null ? null :
Arrays.copyOf(s.mCellBandwidths, s.mCellBandwidths.length);
- mLteEarfcnRsrpBoost = s.mLteEarfcnRsrpBoost;
+ mArfcnRsrpBoost = s.mArfcnRsrpBoost;
synchronized (mNetworkRegistrationInfos) {
mNetworkRegistrationInfos.clear();
mNetworkRegistrationInfos.addAll(s.getNetworkRegistrationInfoList());
@@ -473,7 +475,7 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = in.readInt();
mCdmaEriIconMode = in.readInt();
mIsEmergencyOnly = in.readInt() != 0;
- mLteEarfcnRsrpBoost = in.readInt();
+ mArfcnRsrpBoost = in.readInt();
synchronized (mNetworkRegistrationInfos) {
in.readList(mNetworkRegistrationInfos, NetworkRegistrationInfo.class.getClassLoader());
}
@@ -501,7 +503,7 @@ public class ServiceState implements Parcelable {
out.writeInt(mCdmaEriIconIndex);
out.writeInt(mCdmaEriIconMode);
out.writeInt(mIsEmergencyOnly ? 1 : 0);
- out.writeInt(mLteEarfcnRsrpBoost);
+ out.writeInt(mArfcnRsrpBoost);
synchronized (mNetworkRegistrationInfos) {
out.writeList(mNetworkRegistrationInfos);
}
@@ -890,7 +892,7 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex,
mCdmaEriIconMode,
mIsEmergencyOnly,
- mLteEarfcnRsrpBoost,
+ mArfcnRsrpBoost,
mNetworkRegistrationInfos,
mNrFrequencyRange,
mOperatorAlphaLongRaw,
@@ -1101,7 +1103,7 @@ public class ServiceState implements Parcelable {
.append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
.append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
.append(", isUsingCarrierAggregation=").append(isUsingCarrierAggregation())
- .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
+ .append(", mArfcnRsrpBoost=").append(mArfcnRsrpBoost)
.append(", mNetworkRegistrationInfos=").append(mNetworkRegistrationInfos)
.append(", mNrFrequencyRange=").append(Build.IS_DEBUGGABLE
? mNrFrequencyRange : FREQUENCY_RANGE_UNKNOWN)
@@ -1132,7 +1134,7 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = -1;
mCdmaEriIconMode = -1;
mIsEmergencyOnly = false;
- mLteEarfcnRsrpBoost = 0;
+ mArfcnRsrpBoost = 0;
mNrFrequencyRange = FREQUENCY_RANGE_UNKNOWN;
synchronized (mNetworkRegistrationInfos) {
mNetworkRegistrationInfos.clear();
@@ -1364,7 +1366,7 @@ public class ServiceState implements Parcelable {
m.putBoolean("emergencyOnly", mIsEmergencyOnly);
m.putBoolean("isDataRoamingFromRegistration", getDataRoamingFromRegistration());
m.putBoolean("isUsingCarrierAggregation", isUsingCarrierAggregation());
- m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost);
+ m.putInt("ArfcnRsrpBoost", mArfcnRsrpBoost);
m.putInt("ChannelNumber", mChannelNumber);
m.putIntArray("CellBandwidths", mCellBandwidths);
m.putInt("mNrFrequencyRange", mNrFrequencyRange);
@@ -1455,13 +1457,13 @@ public class ServiceState implements Parcelable {
}
/** @hide */
- public int getLteEarfcnRsrpBoost() {
- return mLteEarfcnRsrpBoost;
+ public int getArfcnRsrpBoost() {
+ return mArfcnRsrpBoost;
}
/** @hide */
- public void setLteEarfcnRsrpBoost(int LteEarfcnRsrpBoost) {
- mLteEarfcnRsrpBoost = LteEarfcnRsrpBoost;
+ public void setArfcnRsrpBoost(int arfcnRsrpBoost) {
+ mArfcnRsrpBoost = arfcnRsrpBoost;
}
/** @hide */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index f7d3f94084ce..549e44c511b9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
@@ -107,7 +106,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
@Test
fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
- @Postsubmit
+ @Presubmit
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
Surface.ROTATION_0)
@@ -116,7 +115,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
@Test
fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
- @Postsubmit
+ @Presubmit
@Test
fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
@@ -126,7 +125,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
}
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() {
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
@@ -140,7 +139,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 8cb3e4a730f1..82ca074b5ef2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -51,7 +51,6 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 185400889)
@Group2
class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
@@ -79,11 +78,11 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
}
}
- @FlakyTest
+ @Presubmit
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- @FlakyTest
+ @Presubmit
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
@@ -109,7 +108,7 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @FlakyTest
+ @Presubmit
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
@@ -130,18 +129,10 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
fun statusBarLayerRotatesScales() {
- Assume.assumeFalse(testSpec.isRotated)
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
}
- @FlakyTest
- @Test
- fun statusBarLayerRotatesScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
- }
-
- @FlakyTest
+ @Presubmit
@Test
fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 08ee6be72bef..703e4a125440 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
@@ -101,7 +100,7 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
}
}
- @Postsubmit
+ @Presubmit
@Test
fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 07d8861088ca..cae1b16c1c8c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
@@ -140,7 +139,7 @@ class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
}
}
- @Postsubmit
+ @Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
testSpec.assertWm {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 432205cf532f..d61422f5d3d0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -17,11 +17,9 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -100,7 +98,7 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
testSpec.assertWm {
@@ -144,19 +142,19 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
fun appLayerReplacesLauncher() =
testSpec.appLayerReplacesLauncher(testAppComponentName.className)
- @FlakyTest
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() {
testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
}
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() {
testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
}
- @Postsubmit
+ @Presubmit
@Test
fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 52850d205b3b..0cae37c8d5ab 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.view.WindowManagerPolicyConstants
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -110,7 +110,7 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
@Test
fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
- @Postsubmit
+ @Presubmit
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
@@ -118,7 +118,7 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 013e844c842e..9ff0bdfe66ba 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -40,7 +40,6 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 185400889)
@Group1
class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
@@ -71,14 +70,32 @@ class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
@FlakyTest
@Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
override fun navBarLayerRotatesAndScales() {
super.navBarLayerRotatesAndScales()
}
@FlakyTest
@Test
- override fun focusChanges() {
- super.focusChanges()
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun appLayerReplacesLauncher() {
+ super.appLayerReplacesLauncher()
+ }
+
+ @FlakyTest
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() {
+ super.appWindowReplacesLauncherAsTopWindow()
}
companion object {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 67d54184c64d..b073a7ca1495 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -26,7 +25,6 @@ import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.launcherWindowBecomesInvisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
import org.junit.Test
@@ -65,15 +63,16 @@ class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransitio
}
}
- @Presubmit
+ @FlakyTest
@Test
- override fun appWindowReplacesLauncherAsTopWindow() =
- super.appWindowReplacesLauncherAsTopWindow()
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
- @Presubmit
+ @FlakyTest
@Test
- override fun launcherWindowBecomesInvisible() {
- testSpec.launcherWindowBecomesInvisible()
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
}
@FlakyTest
@@ -94,18 +93,6 @@ class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransitio
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
- @FlakyTest
- @Test
- override fun focusChanges() {
- super.focusChanges()
- }
-
- @FlakyTest(bugId = 185400889)
- @Test
- override fun noUncoveredRegions() {
- super.noUncoveredRegions()
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 26e77b6c4828..b304d5f999df 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -19,7 +19,6 @@ package com.android.server.wm.flicker.launch
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
@@ -76,13 +75,13 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
testSpec.navBarWindowIsAlwaysVisible()
}
- @FlakyTest
+ @Presubmit
@Test
open fun navBarLayerIsAlwaysVisible() {
testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
}
- @FlakyTest
+ @Presubmit
@Test
open fun navBarLayerRotatesAndScales() {
testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
@@ -94,7 +93,7 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
testSpec.statusBarWindowIsAlwaysVisible()
}
- @FlakyTest
+ @Presubmit
@Test
open fun statusBarLayerIsAlwaysVisible() {
testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
@@ -135,13 +134,13 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
}
- @FlakyTest
+ @Presubmit
@Test
open fun appLayerReplacesLauncher() {
testSpec.appLayerReplacesLauncher(testApp.`package`)
}
- @FlakyTest
+ @Presubmit
@Test
open fun appWindowReplacesLauncherAsTopWindow() {
testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index c6dea00a161a..e2705c764917 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -68,8 +67,8 @@ class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
@FlakyTest
@Test
- override fun focusChanges() {
- super.focusChanges()
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
}
@FlakyTest
@@ -78,24 +77,6 @@ class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
super.navBarLayerRotatesAndScales()
}
- @FlakyTest
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
- @Presubmit
- @Test
- override fun launcherWindowBecomesInvisible() {
- super.launcherWindowBecomesInvisible()
- }
-
- @FlakyTest
- @Test
- override fun noUncoveredRegions() {
- super.noUncoveredRegions()
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index c59dcf879b1c..4ce78aa4d8c1 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -92,10 +92,6 @@ public class VcnGatewayConnectionConfigTest {
builder.addExposedCapability(caps);
}
- for (int caps : UNDERLYING_CAPS) {
- builder.addRequiredUnderlyingCapability(caps);
- }
-
return builder.build();
}
@@ -141,9 +137,7 @@ public class VcnGatewayConnectionConfigTest {
@Test
public void testBuilderRequiresNonEmptyExposedCaps() {
try {
- newBuilder()
- .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
+ newBuilder().build();
fail("Expected exception due to invalid exposed capabilities");
} catch (IllegalArgumentException e) {
@@ -187,10 +181,6 @@ public class VcnGatewayConnectionConfigTest {
Arrays.sort(exposedCaps);
assertArrayEquals(EXPOSED_CAPS, exposedCaps);
- int[] underlyingCaps = config.getRequiredUnderlyingCapabilities();
- Arrays.sort(underlyingCaps);
- assertArrayEquals(UNDERLYING_CAPS, underlyingCaps);
-
assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams());
assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index a36fd797d11c..f91575b670d3 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -61,7 +61,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Set;
import java.util.UUID;
@@ -146,7 +145,6 @@ public class UnderlyingNetworkTrackerTest {
mVcnContext,
SUB_GROUP,
mSubscriptionSnapshot,
- Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET),
mNetworkTrackerCb);
}
@@ -187,7 +185,6 @@ public class UnderlyingNetworkTrackerTest {
vcnContext,
SUB_GROUP,
mSubscriptionSnapshot,
- Collections.singleton(NetworkCapabilities.NET_CAPABILITY_INTERNET),
mNetworkTrackerCb);
verify(cm)
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 0a4fcbcb2842..b97023a95d72 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -177,7 +177,7 @@ public class VcnGatewayConnectionTestBase {
doReturn(mUnderlyingNetworkTracker)
.when(mDeps)
- .newUnderlyingNetworkTracker(any(), any(), any(), any(), any());
+ .newUnderlyingNetworkTracker(any(), any(), any(), any());
doReturn(mWakeLock)
.when(mDeps)
.newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());