summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--TestProtoLibraries.bp36
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java24
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java14
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java22
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java102
-rw-r--r--apex/media/Android.bp5
-rw-r--r--core/java/android/app/ConfigurationController.java5
-rw-r--r--core/java/android/app/WallpaperColors.java114
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java7
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java1
-rw-r--r--core/java/android/app/people/ConversationChannel.java42
-rw-r--r--core/java/android/app/people/PeopleSpaceTile.java8
-rw-r--r--core/java/android/content/res/AssetManager.java36
-rw-r--r--core/java/android/content/res/Resources.java18
-rw-r--r--core/java/android/content/res/ResourcesImpl.java35
-rw-r--r--core/java/android/os/UserManager.java2
-rw-r--r--core/java/android/os/incremental/IncrementalFileStorages.java2
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java12
-rw-r--r--core/java/android/service/voice/SoftwareHotwordDetector.java5
-rw-r--r--core/java/android/service/voice/VoiceInteractionManagerInternal.java37
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java7
-rw-r--r--core/java/android/view/IWindow.aidl11
-rw-r--r--core/java/android/view/ScrollCaptureTarget.java10
-rw-r--r--core/java/android/view/View.java16
-rw-r--r--core/java/android/view/ViewDebug.java12
-rw-r--r--core/java/android/view/ViewRootImpl.java49
-rw-r--r--core/java/android/view/contentcapture/MainContentCaptureSession.java73
-rw-r--r--core/java/android/widget/RemoteViews.java46
-rw-r--r--core/java/android/widget/Toast.java3
-rw-r--r--core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl6
-rw-r--r--core/java/com/android/internal/graphics/palette/CelebiQuantizer.java28
-rw-r--r--core/java/com/android/internal/graphics/palette/LABPointProvider.java (renamed from core/java/com/android/internal/graphics/palette/LABCentroid.java)8
-rw-r--r--core/java/com/android/internal/graphics/palette/Mean.java44
-rw-r--r--core/java/com/android/internal/graphics/palette/MeanBucket.java42
-rw-r--r--core/java/com/android/internal/graphics/palette/PointProvider.java (renamed from core/java/com/android/internal/graphics/palette/CentroidProvider.java)23
-rw-r--r--core/java/com/android/internal/graphics/palette/QuantizerMap.java62
-rw-r--r--core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java398
-rw-r--r--core/java/com/android/internal/graphics/palette/WuQuantizer.java716
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java4
-rw-r--r--core/jni/android_media_AudioSystem.cpp2
-rw-r--r--core/jni/android_util_AssetManager.cpp47
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/res/res/drawable-car/car_checkbox.xml4
-rw-r--r--core/res/res/drawable-car/car_checkbox_background.xml31
-rw-r--r--core/res/res/values-ar/strings.xml6
-rw-r--r--core/res/res/values-az/strings.xml12
-rw-r--r--core/res/res/values-ca/strings.xml2
-rw-r--r--core/res/res/values-cs/strings.xml2
-rw-r--r--core/res/res/values-de/strings.xml2
-rw-r--r--core/res/res/values-es/strings.xml2
-rw-r--r--core/res/res/values-eu/strings.xml18
-rw-r--r--core/res/res/values-fi/strings.xml4
-rw-r--r--core/res/res/values-fr/strings.xml10
-rw-r--r--core/res/res/values-hi/strings.xml2
-rw-r--r--core/res/res/values-hr/strings.xml2
-rw-r--r--core/res/res/values-iw/strings.xml2
-rw-r--r--core/res/res/values-kk/strings.xml14
-rw-r--r--core/res/res/values-kn/strings.xml4
-rw-r--r--core/res/res/values-ko/strings.xml2
-rw-r--r--core/res/res/values-ky/strings.xml6
-rw-r--r--core/res/res/values-mr/strings.xml8
-rw-r--r--core/res/res/values-ne/strings.xml13
-rw-r--r--core/res/res/values-nl/strings.xml2
-rw-r--r--core/res/res/values-or/strings.xml8
-rw-r--r--core/res/res/values-pa/strings.xml5
-rw-r--r--core/res/res/values-pl/strings.xml2
-rw-r--r--core/res/res/values-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-pt/strings.xml4
-rw-r--r--core/res/res/values-sl/strings.xml6
-rw-r--r--core/res/res/values-te/strings.xml2
-rw-r--r--core/res/res/values-uz/strings.xml2
-rw-r--r--core/res/res/values-zh-rCN/strings.xml3
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--keystore/java/android/security/GenerateRkpKey.java68
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java4
-rw-r--r--libs/androidfw/AssetManager2.cpp434
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h21
-rw-r--r--libs/androidfw/tests/Theme_test.cpp74
-rw-r--r--libs/androidfw/tests/data/styles/R.h1
-rw-r--r--libs/androidfw/tests/data/styles/res/values/styles.xml5
-rw-r--r--libs/androidfw/tests/data/styles/styles.apkbin2774 -> 2942 bytes
-rw-r--r--libs/hwui/Readback.cpp8
-rw-r--r--libs/hwui/Readback.h1
-rw-r--r--libs/hwui/jni/Picture.h3
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp111
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp4
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp5
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h2
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp11
-rw-r--r--libs/hwui/renderthread/RenderProxy.h1
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp58
-rw-r--r--media/jni/soundpool/Sound.cpp2
-rw-r--r--packages/DynamicSystemInstallationService/res/values-uz/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-az/strings.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_progress_horizontal.xml37
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml6
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java1
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/Shell/res/values-pa/strings.xml2
-rw-r--r--packages/SystemUI/res/drawable/screenshot_border.xml2
-rw-r--r--packages/SystemUI/res/drawable/screenshot_edit_background.xml2
-rw-r--r--packages/SystemUI/res/drawable/screenshot_save_background.xml2
-rw-r--r--packages/SystemUI/res/layout/global_screenshot.xml5
-rw-r--r--packages/SystemUI/res/layout/global_screenshot_static.xml17
-rw-r--r--packages/SystemUI/res/layout/long_screenshot.xml13
-rw-r--r--packages/SystemUI/res/layout/people_space_placeholder_layout.xml2
-rw-r--r--packages/SystemUI/res/layout/people_tile_medium_with_content.xml6
-rw-r--r--packages/SystemUI/res/layout/volume_ringer_drawer.xml8
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java11
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-af/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-am/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ar/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-as/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-az/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-be/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-bg/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml21
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-bs/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ca/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-cs/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-da/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-de/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-el/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rAU/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rCA/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rGB/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rIN/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rXC/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-es-rUS/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-es/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-et/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-eu/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-fa/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-fi/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-gl/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml21
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-hi/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-hr/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-hu/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-hy/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-in/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-is/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-it/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-iw/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ja/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ka/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-kk/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-km/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-kn/strings.xml21
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ko/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ky/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-lo/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-lt/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-lv/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-mk/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ml/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-mn/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml21
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ms/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-my/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-nb/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml21
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-nl/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-or/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-pa/strings.xml21
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-pl/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ru/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-si/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-sk/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-sl/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-sq/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-sr/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-sv/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-sw/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ta/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml21
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-th/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-tl/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-tr/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-uk/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml21
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-uz/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-vi/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/overlays/AvoidAppsInCutoutOverlay/res/values-zu/strings.xml2
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java4
-rw-r--r--services/core/java/com/android/server/location/provider/AbstractLocationProvider.java4
-rw-r--r--services/core/java/com/android/server/location/provider/MockableLocationProvider.java5
-rw-r--r--services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java33
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java9
-rw-r--r--services/core/java/com/android/server/pm/Settings.java17
-rw-r--r--services/core/java/com/android/server/pm/ShortcutBitmapSaver.java16
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java10
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java92
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java24
-rw-r--r--services/core/java/com/android/server/policy/AppOpsPolicy.java38
-rw-r--r--services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java19
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/Task.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java8
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java172
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java26
-rw-r--r--services/incremental/IncrementalService.cpp31
-rw-r--r--services/incremental/IncrementalService.h1
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp4
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java38
-rw-r--r--services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt59
-rw-r--r--services/tests/mockingservicestests/Android.bp1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java235
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java162
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java98
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java217
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestIWindow.java6
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java32
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java22
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java6
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java62
262 files changed, 3312 insertions, 2331 deletions
diff --git a/Android.bp b/Android.bp
index 2321cc5dd61d..71023bf647c8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -581,4 +581,5 @@ build = [
"StubLibraries.bp",
"ApiDocs.bp",
"ProtoLibraries.bp",
+ "TestProtoLibraries.bp",
]
diff --git a/TestProtoLibraries.bp b/TestProtoLibraries.bp
new file mode 100644
index 000000000000..8e269d0a85c5
--- /dev/null
+++ b/TestProtoLibraries.bp
@@ -0,0 +1,36 @@
+// Copyright 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.
+
+java_library_host {
+ name: "platformtestprotos",
+ srcs: [
+ ":libstats_atom_enum_protos",
+ ":libstats_atom_message_protos",
+ ":libstats_internal_protos",
+ ":statsd_internal_protos",
+ ],
+ libs: [
+ "libprotobuf-java-full",
+ ],
+ proto: {
+ include_dirs: [
+ "external/protobuf/src",
+ "frameworks/proto_logging/stats",
+ ],
+ type: "full",
+ },
+ errorprone: {
+ javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520
+ },
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java
index 6e81afcdc912..d5271a6cb92e 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java
@@ -44,6 +44,8 @@ import java.util.concurrent.Executor;
* @hide
*/
public final class AppSearchConfig implements AutoCloseable {
+ private static volatile AppSearchConfig sConfig;
+
/**
* It would be used as default min time interval between samples in millis if there is no value
* set for {@link AppSearchConfig#KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS} in DeviceConfig.
@@ -101,12 +103,16 @@ public final class AppSearchConfig implements AutoCloseable {
updateCachedValues(properties);
};
+ private AppSearchConfig() {
+ }
+
/**
* Creates an instance of {@link AppSearchConfig}.
*
* @param executor used to fetch and cache the flag values from DeviceConfig during creation or
* config change.
*/
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@NonNull
public static AppSearchConfig create(@NonNull Executor executor) {
Objects.requireNonNull(executor);
@@ -115,7 +121,23 @@ public final class AppSearchConfig implements AutoCloseable {
return configManager;
}
- private AppSearchConfig() {
+ /**
+ * Gets an instance of {@link AppSearchConfig} to be used.
+ *
+ * <p>If no instance has been initialized yet, a new one will be created. Otherwise, the
+ * existing instance will be returned.
+ */
+ @NonNull
+ public static AppSearchConfig getInstance(@NonNull Executor executor) {
+ Objects.requireNonNull(executor);
+ if (sConfig == null) {
+ synchronized (AppSearchConfig.class) {
+ if (sConfig == null) {
+ sConfig = create(executor);
+ }
+ }
+ }
+ return sConfig;
}
/**
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 0709ff5fc48c..a3b89b0f27fb 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -224,7 +224,7 @@ public class AppSearchManagerService extends SystemService {
if (ImplInstanceManager.getAppSearchDir(userHandle).exists()) {
// Only clear the package's data if AppSearch exists for this user.
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(mContext,
- userHandle);
+ userHandle, AppSearchConfig.getInstance(EXECUTOR));
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
userHandle, logger);
//TODO(b/145759910) clear visibility setting for package.
@@ -1147,7 +1147,8 @@ public class AppSearchManagerService extends SystemService {
try {
verifyUserUnlocked(callingUser);
logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
- mContext, callingUser);
+ mContext, callingUser,
+ AppSearchConfig.getInstance(EXECUTOR));
mImplInstanceManager.getOrCreateAppSearchImpl(mContext, callingUser, logger);
++operationSuccessCount;
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
@@ -1313,7 +1314,8 @@ public class AppSearchManagerService extends SystemService {
try {
verifyUserUnlocked(userHandle);
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
- mContext, userHandle);
+ mContext, userHandle,
+ AppSearchConfig.getInstance(EXECUTOR));
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(
mContext, userHandle, logger);
stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
@@ -1341,7 +1343,8 @@ public class AppSearchManagerService extends SystemService {
return;
}
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
- mContext, userHandle);
+ mContext, userHandle,
+ AppSearchConfig.getInstance(EXECUTOR));
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(
mContext, userHandle, logger);
for (int i = 0; i < packagesForUid.length; i++) {
@@ -1370,7 +1373,8 @@ public class AppSearchManagerService extends SystemService {
return;
}
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
- mContext, userHandle);
+ mContext, userHandle,
+ AppSearchConfig.getInstance(EXECUTOR));
AppSearchImpl impl =
mImplInstanceManager.getOrCreateAppSearchImpl(mContext, userHandle, logger);
for (int i = 0; i < packagesForUser.size(); i++) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java
index cb65e42696d1..ea00f506b47f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java
@@ -20,9 +20,9 @@ import android.annotation.NonNull;
import android.content.Context;
import android.os.UserHandle;
import android.util.ArrayMap;
-import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.appsearch.AppSearchConfig;
import com.android.server.appsearch.AppSearchManagerService;
import java.util.Map;
@@ -34,12 +34,6 @@ import java.util.Objects;
* <p>These instances are managed per unique device-user.
*/
public final class LoggerInstanceManager {
- // TODO(b/173532925) flags to control those three
- // So probably we can't pass those three in the constructor but need to fetch the latest value
- // every time we need them in the logger.
- private static final int MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 100;
- private static final int DEFAULT_SAMPLING_RATIO = 10;
-
private static volatile LoggerInstanceManager sLoggerInstanceManager;
@GuardedBy("mInstancesLocked")
@@ -70,23 +64,19 @@ public final class LoggerInstanceManager {
/**
* Gets an instance of PlatformLogger for the given user, or creates one if none exists.
*
- * @param context The context
- * @param userHandle The multi-user handle of the device user calling AppSearch
+ * @param context The context
+ * @param userHandle The multi-user handle of the device user calling AppSearch
* @return An initialized {@link PlatformLogger} for this user
*/
@NonNull
public PlatformLogger getOrCreatePlatformLogger(
- @NonNull Context context, @NonNull UserHandle userHandle) {
+ @NonNull Context context, @NonNull UserHandle userHandle,
+ @NonNull AppSearchConfig config) {
Objects.requireNonNull(userHandle);
synchronized (mInstancesLocked) {
PlatformLogger instance = mInstancesLocked.get(userHandle);
if (instance == null) {
- instance = new PlatformLogger(context, userHandle, new PlatformLogger.Config(
- MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
- DEFAULT_SAMPLING_RATIO,
- // TODO(b/173532925) re-enable sampling ratios for different stats types
- // once we have P/H flag manager setup in ag/13977824
- /*samplingRatios=*/ new SparseIntArray()));
+ instance = new PlatformLogger(context, userHandle, config);
mInstancesLocked.put(userHandle, instance);
}
return instance;
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
index c857fb602eec..26a16a1c061b 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
@@ -29,6 +29,7 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.appsearch.AppSearchConfig;
import com.android.server.appsearch.external.localstorage.AppSearchLogger;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
@@ -60,15 +61,15 @@ public final class PlatformLogger implements AppSearchLogger {
// User we're logging for.
private final UserHandle mUserHandle;
- // Configuration for the logger
- private final Config mConfig;
+ // Manager holding the configuration flags
+ private final AppSearchConfig mConfig;
private final Random mRng = new Random();
private final Object mLock = new Object();
/**
* SparseArray to track how many stats we skipped due to
- * {@link Config#mMinTimeIntervalBetweenSamplesMillis}.
+ * {@link AppSearchConfig#getCachedMinTimeIntervalBetweenSamplesMillis()}.
*
* <p> We can have correct extrapolated number by adding those counts back when we log
* the same type of stats next time. E.g. the true count of an event could be estimated as:
@@ -98,53 +99,6 @@ public final class PlatformLogger implements AppSearchLogger {
private long mLastPushTimeMillisLocked = 0;
/**
- * Class to configure the {@link PlatformLogger}
- */
- public static final class Config {
- // Minimum time interval (in millis) since last message logged to Westworld before
- // logging again.
- private final long mMinTimeIntervalBetweenSamplesMillis;
-
- // Default sampling interval for all types of stats
- private final int mDefaultSamplingInterval;
-
- /**
- * Sampling intervals for different types of stats
- *
- * <p>This SparseArray is passed by client and is READ-ONLY. The key to that SparseArray is
- * {@link CallStats.CallType}
- *
- * <p>If sampling interval is missing for certain stats type,
- * {@link Config#mDefaultSamplingInterval} will be used.
- *
- * <p>E.g. sampling interval=10 means that one out of every 10 stats was logged. If sampling
- * interval is 1, we will log each sample and it acts as if the sampling is disabled.
- */
- @NonNull
- private final SparseIntArray mSamplingIntervals;
-
- /**
- * Configuration for {@link PlatformLogger}
- *
- * @param minTimeIntervalBetweenSamplesMillis minimum time interval apart in Milliseconds
- * required for two consecutive stats logged
- * @param defaultSamplingInterval default sampling interval
- * @param samplingIntervals SparseArray to customize sampling interval for
- * different stat types
- */
- public Config(long minTimeIntervalBetweenSamplesMillis,
- int defaultSamplingInterval,
- @NonNull SparseIntArray samplingIntervals) {
- // TODO(b/173532925) Probably we can get rid of those three after we have p/h flags
- // for them.
- // e.g. we can just call DeviceConfig.get(SAMPLING_INTERVAL_FOR_PUT_DOCUMENTS).
- mMinTimeIntervalBetweenSamplesMillis = minTimeIntervalBetweenSamplesMillis;
- mDefaultSamplingInterval = defaultSamplingInterval;
- mSamplingIntervals = samplingIntervals;
- }
- }
-
- /**
* Helper class to hold platform specific stats for Westworld.
*/
static final class ExtraStats {
@@ -166,7 +120,8 @@ public final class PlatformLogger implements AppSearchLogger {
* Westworld constructor
*/
public PlatformLogger(
- @NonNull Context context, @NonNull UserHandle userHandle, @NonNull Config config) {
+ @NonNull Context context, @NonNull UserHandle userHandle,
+ @NonNull AppSearchConfig config) {
mContext = Objects.requireNonNull(context);
mUserHandle = Objects.requireNonNull(userHandle);
mConfig = Objects.requireNonNull(config);
@@ -372,7 +327,9 @@ public final class PlatformLogger implements AppSearchLogger {
stats.getSchemaStoreRecoveryLatencyMillis(),
stats.getDocumentStoreDataStatus(),
stats.getDocumentCount(),
- stats.getSchemaTypeCount());
+ stats.getSchemaTypeCount(),
+ stats.hasReset(),
+ stats.getResetStatusCode());
}
/**
@@ -428,9 +385,12 @@ public final class PlatformLogger implements AppSearchLogger {
packageUid = getPackageUidAsUserLocked(packageName);
}
- int samplingInterval = mConfig.mSamplingIntervals.get(callType,
- mConfig.mDefaultSamplingInterval);
-
+ // The sampling ratio here might be different from the one used in
+ // shouldLogForTypeLocked if there is a config change in the middle.
+ // Since it is only one sample, we can just ignore this difference.
+ // Or we can retrieve samplingRatio at beginning and pass along
+ // as function parameter, but it will make code less cleaner with some duplication.
+ int samplingInterval = getSamplingIntervalFromConfig(callType);
int skippedSampleCount = mSkippedSampleCountLocked.get(callType,
/*valueOfKeyIfNotFound=*/ 0);
mSkippedSampleCountLocked.put(callType, 0);
@@ -450,9 +410,7 @@ public final class PlatformLogger implements AppSearchLogger {
// rate limiting.
@VisibleForTesting
boolean shouldLogForTypeLocked(@CallStats.CallType int callType) {
- int samplingInterval = mConfig.mSamplingIntervals.get(callType,
- mConfig.mDefaultSamplingInterval);
-
+ int samplingInterval = getSamplingIntervalFromConfig(callType);
// Sampling
if (!shouldSample(samplingInterval)) {
return false;
@@ -462,7 +420,7 @@ public final class PlatformLogger implements AppSearchLogger {
// Check the timestamp to see if it is too close to last logged sample
long currentTimeMillis = SystemClock.elapsedRealtime();
if (mLastPushTimeMillisLocked
- > currentTimeMillis - mConfig.mMinTimeIntervalBetweenSamplesMillis) {
+ > currentTimeMillis - mConfig.getCachedMinTimeIntervalBetweenSamplesMillis()) {
int count = mSkippedSampleCountLocked.get(callType, /*valueOfKeyIfNotFound=*/ 0);
++count;
mSkippedSampleCountLocked.put(callType, count);
@@ -502,6 +460,32 @@ public final class PlatformLogger implements AppSearchLogger {
return packageUid;
}
+ /** Returns sampling ratio for stats type specified form {@link AppSearchConfig}. */
+ private int getSamplingIntervalFromConfig(@CallStats.CallType int statsType) {
+ switch (statsType) {
+ case CallStats.CALL_TYPE_PUT_DOCUMENTS:
+ case CallStats.CALL_TYPE_GET_DOCUMENTS:
+ case CallStats.CALL_TYPE_REMOVE_DOCUMENTS_BY_ID:
+ case CallStats.CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH:
+ return mConfig.getCachedSamplingIntervalForBatchCallStats();
+ case CallStats.CALL_TYPE_PUT_DOCUMENT:
+ return mConfig.getCachedSamplingIntervalForPutDocumentStats();
+ case CallStats.CALL_TYPE_UNKNOWN:
+ case CallStats.CALL_TYPE_INITIALIZE:
+ case CallStats.CALL_TYPE_SET_SCHEMA:
+ case CallStats.CALL_TYPE_GET_DOCUMENT:
+ case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_ID:
+ case CallStats.CALL_TYPE_SEARCH:
+ case CallStats.CALL_TYPE_OPTIMIZE:
+ case CallStats.CALL_TYPE_FLUSH:
+ case CallStats.CALL_TYPE_GLOBAL_SEARCH:
+ case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH:
+ // TODO(b/173532925) Some of them above will have dedicated sampling ratio config
+ default:
+ return mConfig.getCachedSamplingIntervalDefault();
+ }
+ }
+
//
// Functions below are used for tests only
//
diff --git a/apex/media/Android.bp b/apex/media/Android.bp
index 2b4b3f0f52e8..f2e64ce0b2c5 100644
--- a/apex/media/Android.bp
+++ b/apex/media/Android.bp
@@ -28,5 +28,8 @@ package {
sdk {
name: "media-module-sdk",
bootclasspath_fragments: ["com.android.media-bootclasspath-fragment"],
- java_sdk_libs: ["service-media-s"],
+ java_sdk_libs: [
+ "framework-media",
+ "service-media-s",
+ ],
}
diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java
index 6d92201db8ec..f79e0780ecae 100644
--- a/core/java/android/app/ConfigurationController.java
+++ b/core/java/android/app/ConfigurationController.java
@@ -158,10 +158,9 @@ class ConfigurationController {
int configDiff;
boolean equivalent;
- final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
- final Resources.Theme systemUiTheme = mActivityThread.getSystemUiContext().getTheme();
-
synchronized (mResourcesManager) {
+ final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
+ final Resources.Theme systemUiTheme = mActivityThread.getSystemUiContext().getTheme();
if (mPendingConfiguration != null) {
if (!mPendingConfiguration.isOtherSeqNewer(config)) {
config = mPendingConfiguration;
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index edd60473c522..cd82deb13e9b 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -30,6 +30,7 @@ import android.util.Log;
import android.util.Size;
import com.android.internal.graphics.ColorUtils;
+import com.android.internal.graphics.cam.Cam;
import com.android.internal.graphics.palette.CelebiQuantizer;
import com.android.internal.graphics.palette.Palette;
import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
@@ -43,7 +44,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
+import java.util.Set;
/**
* Provides information about the colors of a wallpaper.
@@ -176,7 +177,7 @@ public final class WallpaperColors implements Parcelable {
shouldRecycle = true;
Size optimalSize = calculateOptimalSize(bitmap.getWidth(), bitmap.getHeight());
bitmap = Bitmap.createScaledBitmap(bitmap, optimalSize.getWidth(),
- optimalSize.getHeight(), true /* filter */);
+ optimalSize.getHeight(), false /* filter */);
}
final Palette palette;
@@ -189,7 +190,7 @@ public final class WallpaperColors implements Parcelable {
} else {
palette = Palette
.from(bitmap, new CelebiQuantizer())
- .maximumColorCount(5)
+ .maximumColorCount(128)
.resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
.generate();
}
@@ -278,7 +279,7 @@ public final class WallpaperColors implements Parcelable {
/**
* Constructs a new object from a set of colors, where hints can be specified.
*
- * @param populationByColor Map with keys of colors, and value representing the number of
+ * @param colorToPopulation Map with keys of colors, and value representing the number of
* occurrences of color in the wallpaper.
* @param colorHints A combination of color hints.
* @hide
@@ -286,20 +287,105 @@ public final class WallpaperColors implements Parcelable {
* @see WallpaperColors#fromBitmap(Bitmap)
* @see WallpaperColors#fromDrawable(Drawable)
*/
- public WallpaperColors(@NonNull Map<Integer, Integer> populationByColor,
+ public WallpaperColors(@NonNull Map<Integer, Integer> colorToPopulation,
@ColorsHints int colorHints) {
- mAllColors = populationByColor;
-
- ArrayList<Map.Entry<Integer, Integer>> mapEntries = new ArrayList(
- populationByColor.entrySet());
- mapEntries.sort((a, b) ->
- a.getValue().compareTo(b.getValue())
- );
- mMainColors = mapEntries.stream().map(entry -> Color.valueOf(entry.getKey())).collect(
- Collectors.toList());
+ mAllColors = colorToPopulation;
+
+ final Map<Integer, Cam> colorToCam = new HashMap<>();
+ for (int color : colorToPopulation.keySet()) {
+ colorToCam.put(color, Cam.fromInt(color));
+ }
+ final double[] hueProportions = hueProportions(colorToCam, colorToPopulation);
+ final Map<Integer, Double> colorToHueProportion = colorToHueProportion(
+ colorToPopulation.keySet(), colorToCam, hueProportions);
+
+ final Map<Integer, Double> colorToScore = new HashMap<>();
+ for (Map.Entry<Integer, Double> mapEntry : colorToHueProportion.entrySet()) {
+ int color = mapEntry.getKey();
+ double proportion = mapEntry.getValue();
+ double score = score(colorToCam.get(color), proportion);
+ colorToScore.put(color, score);
+ }
+ ArrayList<Map.Entry<Integer, Double>> mapEntries = new ArrayList(colorToScore.entrySet());
+ mapEntries.sort((a, b) -> b.getValue().compareTo(a.getValue()));
+
+ List<Integer> colorsByScoreDescending = new ArrayList<>();
+ for (Map.Entry<Integer, Double> colorToScoreEntry : mapEntries) {
+ colorsByScoreDescending.add(colorToScoreEntry.getKey());
+ }
+
+ List<Integer> mainColorInts = new ArrayList<>();
+ findSeedColorLoop:
+ for (int color : colorsByScoreDescending) {
+ Cam cam = colorToCam.get(color);
+ for (int otherColor : mainColorInts) {
+ Cam otherCam = colorToCam.get(otherColor);
+ if (hueDiff(cam, otherCam) < 15) {
+ continue findSeedColorLoop;
+ }
+ }
+ mainColorInts.add(color);
+ }
+ List<Color> mainColors = new ArrayList<>();
+ for (int colorInt : mainColorInts) {
+ mainColors.add(Color.valueOf(colorInt));
+ }
+ mMainColors = mainColors;
mColorHints = colorHints;
}
+ private static double hueDiff(Cam a, Cam b) {
+ return (180f - Math.abs(Math.abs(a.getHue() - b.getHue()) - 180f));
+ }
+
+ private static double score(Cam cam, double proportion) {
+ return cam.getChroma() + (proportion * 100);
+ }
+
+ private static Map<Integer, Double> colorToHueProportion(Set<Integer> colors,
+ Map<Integer, Cam> colorToCam, double[] hueProportions) {
+ Map<Integer, Double> colorToHueProportion = new HashMap<>();
+ for (int color : colors) {
+ final int hue = wrapDegrees(Math.round(colorToCam.get(color).getHue()));
+ double proportion = 0.0;
+ for (int i = hue - 15; i < hue + 15; i++) {
+ proportion += hueProportions[wrapDegrees(i)];
+ }
+ colorToHueProportion.put(color, proportion);
+ }
+ return colorToHueProportion;
+ }
+
+ private static int wrapDegrees(int degrees) {
+ if (degrees < 0) {
+ return (degrees % 360) + 360;
+ } else if (degrees >= 360) {
+ return degrees % 360;
+ } else {
+ return degrees;
+ }
+ }
+
+ private static double[] hueProportions(@NonNull Map<Integer, Cam> colorToCam,
+ Map<Integer, Integer> colorToPopulation) {
+ final double[] proportions = new double[360];
+
+ double totalPopulation = 0;
+ for (Map.Entry<Integer, Integer> entry : colorToPopulation.entrySet()) {
+ totalPopulation += entry.getValue();
+ }
+
+ for (Map.Entry<Integer, Integer> entry : colorToPopulation.entrySet()) {
+ final int color = (int) entry.getKey();
+ final int population = colorToPopulation.get(color);
+ final Cam cam = colorToCam.get(color);
+ final int hue = wrapDegrees(Math.round(cam.getHue()));
+ proportions[hue] = proportions[hue] + ((double) population / totalPopulation);
+ }
+
+ return proportions;
+ }
+
public static final @android.annotation.NonNull Creator<WallpaperColors> CREATOR = new Creator<WallpaperColors>() {
@Override
public WallpaperColors createFromParcel(Parcel in) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5b65795612d0..8c9e771dbd73 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6845,6 +6845,10 @@ public class DevicePolicyManager {
* <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure
* of the VPN provider could break networking for all apps. This method clears any lockdown
* allowlist set by {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)}.
+ * <p> Starting from {@link android.os.Build.VERSION_CODES#S API 31} calling this method with
+ * {@code vpnPackage} set to {@code null} only removes the existing configuration if it was
+ * previously created by this admin. To remove VPN configuration created by the user use
+ * {@link UserManager#DISALLOW_CONFIG_VPN}.
*
* @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to
* remove an existing always-on VPN configuration.
@@ -13876,8 +13880,7 @@ public class DevicePolicyManager {
}
/**
- * Called by device owner or profile owner of an organization-owned managed profile to return
- * whether USB data signaling is currently enabled by the admin.
+ * Returns whether USB data signaling is currently enabled by the admin. Callable by any app.
*
* @return {@code true} if USB data signaling is enabled, {@code false} otherwise.
*/
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 67f5c366bc14..a9bec98ce405 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -265,5 +265,4 @@ public abstract class DevicePolicyManagerInternal {
*/
public abstract void notifyUnsafeOperationStateChanged(DevicePolicySafetyChecker checker,
@OperationSafetyReason int reason, boolean isSafe);
-
}
diff --git a/core/java/android/app/people/ConversationChannel.java b/core/java/android/app/people/ConversationChannel.java
index 332e159679ae..2bf71b0183c6 100644
--- a/core/java/android/app/people/ConversationChannel.java
+++ b/core/java/android/app/people/ConversationChannel.java
@@ -36,8 +36,8 @@ public final class ConversationChannel implements Parcelable {
private ShortcutInfo mShortcutInfo;
private int mUid;
- private NotificationChannel mParentNotificationChannel;
- private NotificationChannelGroup mParentNotificationChannelGroup;
+ private NotificationChannel mNotificationChannel;
+ private NotificationChannelGroup mNotificationChannelGroup;
private long mLastEventTimestamp;
private boolean mHasActiveNotifications;
private boolean mHasBirthdayToday;
@@ -61,8 +61,8 @@ public final class ConversationChannel implements Parcelable {
boolean hasActiveNotifications) {
mShortcutInfo = shortcutInfo;
mUid = uid;
- mParentNotificationChannel = parentNotificationChannel;
- mParentNotificationChannelGroup = parentNotificationChannelGroup;
+ mNotificationChannel = parentNotificationChannel;
+ mNotificationChannelGroup = parentNotificationChannelGroup;
mLastEventTimestamp = lastEventTimestamp;
mHasActiveNotifications = hasActiveNotifications;
}
@@ -74,8 +74,8 @@ public final class ConversationChannel implements Parcelable {
List<ConversationStatus> statuses) {
mShortcutInfo = shortcutInfo;
mUid = uid;
- mParentNotificationChannel = parentNotificationChannel;
- mParentNotificationChannelGroup = parentNotificationChannelGroup;
+ mNotificationChannel = parentNotificationChannel;
+ mNotificationChannelGroup = parentNotificationChannelGroup;
mLastEventTimestamp = lastEventTimestamp;
mHasActiveNotifications = hasActiveNotifications;
mHasBirthdayToday = hasBirthdayToday;
@@ -85,8 +85,8 @@ public final class ConversationChannel implements Parcelable {
public ConversationChannel(Parcel in) {
mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
mUid = in.readInt();
- mParentNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader());
- mParentNotificationChannelGroup =
+ mNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader());
+ mNotificationChannelGroup =
in.readParcelable(NotificationChannelGroup.class.getClassLoader());
mLastEventTimestamp = in.readLong();
mHasActiveNotifications = in.readBoolean();
@@ -104,8 +104,8 @@ public final class ConversationChannel implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(mShortcutInfo, flags);
dest.writeInt(mUid);
- dest.writeParcelable(mParentNotificationChannel, flags);
- dest.writeParcelable(mParentNotificationChannelGroup, flags);
+ dest.writeParcelable(mNotificationChannel, flags);
+ dest.writeParcelable(mNotificationChannelGroup, flags);
dest.writeLong(mLastEventTimestamp);
dest.writeBoolean(mHasActiveNotifications);
dest.writeBoolean(mHasBirthdayToday);
@@ -120,12 +120,12 @@ public final class ConversationChannel implements Parcelable {
return mUid;
}
- public NotificationChannel getParentNotificationChannel() {
- return mParentNotificationChannel;
+ public NotificationChannel getNotificationChannel() {
+ return mNotificationChannel;
}
- public NotificationChannelGroup getParentNotificationChannelGroup() {
- return mParentNotificationChannelGroup;
+ public NotificationChannelGroup getNotificationChannelGroup() {
+ return mNotificationChannelGroup;
}
public long getLastEventTimestamp() {
@@ -149,4 +149,18 @@ public final class ConversationChannel implements Parcelable {
public @Nullable List<ConversationStatus> getStatuses() {
return mStatuses;
}
+
+ @Override
+ public String toString() {
+ return "ConversationChannel{" +
+ "mShortcutInfo=" + mShortcutInfo +
+ ", mUid=" + mUid +
+ ", mNotificationChannel=" + mNotificationChannel +
+ ", mNotificationChannelGroup=" + mNotificationChannelGroup +
+ ", mLastEventTimestamp=" + mLastEventTimestamp +
+ ", mHasActiveNotifications=" + mHasActiveNotifications +
+ ", mHasBirthdayToday=" + mHasBirthdayToday +
+ ", mStatuses=" + mStatuses +
+ '}';
+ }
}
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index 2dbbfdf660aa..e11861f49be8 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -307,10 +307,10 @@ public class PeopleSpaceTile implements Parcelable {
mContactUri = getContactUri(info);
mStatuses = channel.getStatuses();
mLastInteractionTimestamp = channel.getLastEventTimestamp();
- mIsImportantConversation = channel.getParentNotificationChannel() != null
- && channel.getParentNotificationChannel().isImportantConversation();
- mCanBypassDnd = channel.getParentNotificationChannel() != null
- && channel.getParentNotificationChannel().canBypassDnd();
+ mIsImportantConversation = channel.getNotificationChannel() != null
+ && channel.getNotificationChannel().isImportantConversation();
+ mCanBypassDnd = channel.getNotificationChannel() != null
+ && channel.getNotificationChannel().canBypassDnd();
mNotificationPolicyState = SHOW_CONVERSATIONS;
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index d50404e94544..24c6a5a12178 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -43,6 +43,7 @@ import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.ref.Reference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -1178,11 +1179,14 @@ public final class AssetManager implements AutoCloseable {
void releaseTheme(long themePtr) {
synchronized (this) {
- nativeThemeDestroy(themePtr);
decRefsLocked(themePtr);
}
}
+ static long getThemeFreeFunction() {
+ return nativeGetThemeFreeFunction();
+ }
+
void applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force) {
synchronized (this) {
// Need to synchronize on AssetManager because we will be accessing
@@ -1192,6 +1196,31 @@ public final class AssetManager implements AutoCloseable {
}
}
+ AssetManager rebaseTheme(long themePtr, @NonNull AssetManager newAssetManager,
+ @StyleRes int[] styleIds, @StyleRes boolean[] force, int count) {
+ // Exchange ownership of the theme with the new asset manager.
+ if (this != newAssetManager) {
+ synchronized (this) {
+ ensureValidLocked();
+ decRefsLocked(themePtr);
+ }
+ synchronized (newAssetManager) {
+ newAssetManager.ensureValidLocked();
+ newAssetManager.incRefsLocked(themePtr);
+ }
+ }
+
+ try {
+ synchronized (newAssetManager) {
+ newAssetManager.ensureValidLocked();
+ nativeThemeRebase(newAssetManager.mObject, themePtr, styleIds, force, count);
+ }
+ } finally {
+ Reference.reachabilityFence(newAssetManager);
+ }
+ return newAssetManager;
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
void setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr) {
synchronized (this) {
@@ -1559,12 +1588,13 @@ public final class AssetManager implements AutoCloseable {
// Theme related native methods
private static native long nativeThemeCreate(long ptr);
- private static native void nativeThemeDestroy(long themePtr);
+ private static native long nativeGetThemeFreeFunction();
private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId,
boolean force);
+ private static native void nativeThemeRebase(long ptr, long themePtr, @NonNull int[] styleIds,
+ @NonNull boolean[] force, int styleSize);
private static native void nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr,
long srcAssetManagerPtr, long srcThemePtr);
- static native void nativeThemeClear(long themePtr);
private static native int nativeThemeGetAttributeValue(long ptr, long themePtr,
@AttrRes int resId, @NonNull TypedValue outValue, boolean resolve);
private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag,
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ac4b7b7dc158..12e41e299e16 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -341,7 +341,7 @@ public class Resources {
/**
* Set the underlying implementation (containing all the resources and caches)
- * and updates all Theme references to new implementations as well.
+ * and updates all Theme implementations as well.
* @hide
*/
@UnsupportedAppUsage
@@ -353,14 +353,14 @@ public class Resources {
mBaseApkAssetsSize = ArrayUtils.size(impl.getAssets().getApkAssets());
mResourcesImpl = impl;
- // Create new ThemeImpls that are identical to the ones we have.
+ // Rebase the ThemeImpls using the new ResourcesImpl.
synchronized (mThemeRefs) {
final int count = mThemeRefs.size();
for (int i = 0; i < count; i++) {
WeakReference<Theme> weakThemeRef = mThemeRefs.get(i);
Theme theme = weakThemeRef != null ? weakThemeRef.get() : null;
if (theme != null) {
- theme.setNewResourcesImpl(mResourcesImpl);
+ theme.rebase(mResourcesImpl);
}
}
}
@@ -1515,12 +1515,6 @@ public class Resources {
}
}
- void setNewResourcesImpl(ResourcesImpl resImpl) {
- synchronized (mLock) {
- mThemeImpl = resImpl.newThemeImpl(mThemeImpl.getKey());
- }
- }
-
/**
* Place new attribute values into the theme. The style resource
* specified by <var>resid</var> will be retrieved from this Theme's
@@ -1847,6 +1841,12 @@ public class Resources {
}
}
+ void rebase(ResourcesImpl resImpl) {
+ synchronized (mLock) {
+ mThemeImpl.rebase(resImpl.mAssets);
+ }
+ }
+
/**
* Returns the resource ID for the style specified using {@code style="..."} in the
* {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 553e11b46da5..b9f93b85f0bf 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -54,6 +54,8 @@ import android.view.DisplayAdjustments;
import com.android.internal.util.GrowingArrayUtils;
+import libcore.util.NativeAllocationRegistry;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -1265,15 +1267,9 @@ public class ResourcesImpl {
return new ThemeImpl();
}
- /**
- * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey.
- */
- ThemeImpl newThemeImpl(Resources.ThemeKey key) {
- ThemeImpl impl = new ThemeImpl();
- impl.mKey.setTo(key);
- impl.rebase();
- return impl;
- }
+ private static final NativeAllocationRegistry sThemeRegistry =
+ NativeAllocationRegistry.createMalloced(ResourcesImpl.class.getClassLoader(),
+ AssetManager.getThemeFreeFunction());
public class ThemeImpl {
/**
@@ -1282,7 +1278,7 @@ public class ResourcesImpl {
private final Resources.ThemeKey mKey = new Resources.ThemeKey();
@SuppressWarnings("hiding")
- private final AssetManager mAssets;
+ private AssetManager mAssets;
private final long mTheme;
/**
@@ -1293,6 +1289,7 @@ public class ResourcesImpl {
/*package*/ ThemeImpl() {
mAssets = ResourcesImpl.this.mAssets;
mTheme = mAssets.createTheme();
+ sThemeRegistry.registerNativeAllocation(this, mTheme);
}
@Override
@@ -1404,14 +1401,18 @@ public class ResourcesImpl {
* {@link #applyStyle(int, boolean)}.
*/
void rebase() {
- AssetManager.nativeThemeClear(mTheme);
+ rebase(mAssets);
+ }
- // Reapply the same styles in the same order.
- for (int i = 0; i < mKey.mCount; i++) {
- final int resId = mKey.mResId[i];
- final boolean force = mKey.mForce[i];
- mAssets.applyStyleToTheme(mTheme, resId, force);
- }
+ /**
+ * Rebases the theme against the {@code newAssets} by re-applying the styles passed to
+ * {@link #applyStyle(int, boolean)}.
+ *
+ * The theme will use {@code newAssets} for all future invocations of
+ * {@link #applyStyle(int, boolean)}.
+ */
+ void rebase(AssetManager newAssets) {
+ mAssets = mAssets.rebaseTheme(mTheme, newAssets, mKey.mResId, mKey.mForce, mKey.mCount);
}
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 224cd84bc777..c22224dd0da2 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -575,6 +575,8 @@ public class UserManager {
* <p>This restriction also prevents VPNs from starting. However, in Android 7.0
* ({@linkplain android.os.Build.VERSION_CODES#N API level 24}) or higher, the system does
* start always-on VPNs created by the device or profile owner.
+ * <p>From Android 12 ({@linkplain android.os.Build.VERSION_CODES#S API level 31}) enforcing
+ * this restriction clears currently active VPN if it was configured by the user.
*
* <p>Key for user restrictions.
* <p>Type: Boolean
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 6e25968192ae..8ebc0814a3dc 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -160,7 +160,7 @@ public final class IncrementalFileStorages {
/**
* Starts or re-starts loading of data.
*/
- void startLoading(
+ public void startLoading(
@NonNull DataLoaderParams dataLoaderParams,
@Nullable IDataLoaderStatusListener statusListener,
@Nullable StorageHealthCheckParams healthCheckParams,
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index fed28df964d6..67b97cee1b51 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -354,6 +354,13 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
null);
}
+ EventPayload(boolean triggerAvailable, boolean captureAvailable,
+ AudioFormat audioFormat, int captureSession, byte[] data,
+ HotwordDetectedResult hotwordDetectedResult) {
+ this(triggerAvailable, captureAvailable, audioFormat, captureSession, data,
+ hotwordDetectedResult, null);
+ }
+
EventPayload(AudioFormat audioFormat, HotwordDetectedResult hotwordDetectedResult) {
this(false, false, audioFormat, -1, null, hotwordDetectedResult, null);
}
@@ -1149,7 +1156,8 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
@Override
- public void onKeyphraseDetected(KeyphraseRecognitionEvent event) {
+ public void onKeyphraseDetected(
+ KeyphraseRecognitionEvent event, HotwordDetectedResult result) {
if (DBG) {
Slog.d(TAG, "onDetected(" + event + ")");
} else {
@@ -1157,7 +1165,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
}
Message.obtain(mHandler, MSG_HOTWORD_DETECTED,
new EventPayload(event.triggerInData, event.captureAvailable,
- event.captureFormat, event.captureSession, event.data))
+ event.captureFormat, event.captureSession, event.data, result))
.sendToTarget();
}
@Override
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 47f2c6403757..204e7df89706 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -147,8 +147,9 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
}
@Override
- public void onKeyphraseDetected(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent)
- throws RemoteException {
+ public void onKeyphraseDetected(
+ SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
+ HotwordDetectedResult result) {
}
diff --git a/core/java/android/service/voice/VoiceInteractionManagerInternal.java b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
index f5c959137d9b..c048286545c3 100644
--- a/core/java/android/service/voice/VoiceInteractionManagerInternal.java
+++ b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
@@ -16,9 +16,12 @@
package android.service.voice;
+import android.annotation.Nullable;
import android.os.Bundle;
import android.os.IBinder;
+import com.android.internal.annotations.Immutable;
+
/**
* @hide
@@ -46,4 +49,38 @@ public abstract class VoiceInteractionManagerInternal {
* Returns whether the given package is currently in an active session
*/
public abstract boolean hasActiveSession(String packageName);
+
+ /**
+ * Gets the identity of the currently active HotwordDetectionService.
+ *
+ * @see HotwordDetectionServiceIdentity
+ */
+ @Nullable
+ public abstract HotwordDetectionServiceIdentity getHotwordDetectionServiceIdentity();
+
+ /**
+ * Provides the uids of the currently active
+ * {@link android.service.voice.HotwordDetectionService} and its owning package. The
+ * HotwordDetectionService is an isolated service, so it has a separate uid.
+ */
+ @Immutable
+ public static class HotwordDetectionServiceIdentity {
+ private final int mIsolatedUid;
+ private final int mOwnerUid;
+
+ public HotwordDetectionServiceIdentity(int isolatedUid, int ownerUid) {
+ mIsolatedUid = isolatedUid;
+ mOwnerUid = ownerUid;
+ }
+
+ /** Gets the uid of the currently active isolated process hosting the service. */
+ public int getIsolatedUid() {
+ return mIsolatedUid;
+ }
+
+ /** Gets the uid of the package that provides the HotwordDetectionService. */
+ public int getOwnerUid() {
+ return mOwnerUid;
+ }
+ }
} \ No newline at end of file
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 603df1e32e8b..05ed75a7d8fb 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1511,9 +1511,12 @@ public abstract class WallpaperService extends Service {
void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
float xOffsetStep) {
// to save creating a runnable, check twice
- long current = System.nanoTime() / 1_000_000;
+ long current = SystemClock.elapsedRealtime();
long lapsed = current - currentPage.getLastUpdateTime();
- if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) {
+ // Always update the page when the last update time is <= 0
+ // This is important especially when the device first boots
+ if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION
+ && currentPage.getLastUpdateTime() > 0) {
return;
}
Surface surface = mSurfaceHolder.getSurface();
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 8d59ba0b1f76..b8b13b9ed88a 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -65,13 +65,20 @@ oneway interface IWindow {
/**
* Called when the window insets configuration has changed.
+ *
+ * @param willMove The window frame will be moved soon.
+ * @param willResize The window frame will be resized soon.
*/
- void insetsChanged(in InsetsState insetsState);
+ void insetsChanged(in InsetsState insetsState, in boolean willMove, in boolean willResize);
/**
* Called when this window retrieved control over a specified set of insets sources.
+ *
+ * @param willMove The window frame will be moved soon.
+ * @param willResize The window frame will be resized soon.
*/
- void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls);
+ void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls,
+ in boolean willMove, in boolean willResize);
/**
* Called when a set of insets source window should be shown by policy.
diff --git a/core/java/android/view/ScrollCaptureTarget.java b/core/java/android/view/ScrollCaptureTarget.java
index 4fd48892da70..44017ed0d831 100644
--- a/core/java/android/view/ScrollCaptureTarget.java
+++ b/core/java/android/view/ScrollCaptureTarget.java
@@ -16,6 +16,8 @@
package android.view;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
@@ -46,11 +48,11 @@ public final class ScrollCaptureTarget {
public ScrollCaptureTarget(@NonNull View scrollTarget, @NonNull Rect localVisibleRect,
@NonNull Point positionInWindow, @NonNull ScrollCaptureCallback callback) {
- mContainingView = scrollTarget;
+ mContainingView = requireNonNull(scrollTarget);
mHint = mContainingView.getScrollCaptureHint();
- mCallback = callback;
- mLocalVisibleRect = localVisibleRect;
- mPositionInWindow = positionInWindow;
+ mCallback = requireNonNull(callback);
+ mLocalVisibleRect = requireNonNull(localVisibleRect);
+ mPositionInWindow = requireNonNull(positionInWindow);
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8138b3d30ddf..6d861dd00e9c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9808,23 +9808,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) {
AttachInfo ai = mAttachInfo;
- // Skip it while the view is being laided out for the first time
+ // Skip it while the view is being laid out for the first time
if (ai != null && !ai.mReadyForContentCaptureUpdates) return;
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
- Trace.traceBegin(Trace.TRACE_TAG_VIEW,
- "notifyContentCapture(" + appeared + ") for " + getClass().getSimpleName());
- }
- try {
- notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(appeared);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
- }
-
- private void notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(boolean appeared) {
- AttachInfo ai = mAttachInfo;
-
// First check if context has client, so it saves a service lookup when it doesn't
if (mContext.getContentCaptureOptions() == null) return;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 538b8888fa70..73294b3ac969 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -953,8 +953,7 @@ public class ViewDebug {
private final Callable<OutputStream> mCallback;
private final Executor mExecutor;
private final ReentrantLock mLock = new ReentrantLock(false);
- private final ArrayDeque<byte[]> mQueue = new ArrayDeque<>(3);
- private final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream();
+ private final ArrayDeque<Picture> mQueue = new ArrayDeque<>(3);
private boolean mStopListening;
private Thread mRenderThread;
@@ -990,9 +989,7 @@ public class ViewDebug {
mQueue.removeLast();
needsInvoke = false;
}
- picture.writeToStream(mByteStream);
- mQueue.add(mByteStream.toByteArray());
- mByteStream.reset();
+ mQueue.add(picture);
mLock.unlock();
if (needsInvoke) {
@@ -1003,7 +1000,7 @@ public class ViewDebug {
@Override
public void run() {
mLock.lock();
- final byte[] picture = mQueue.poll();
+ final Picture picture = mQueue.poll();
final boolean isStopped = mStopListening;
mLock.unlock();
if (Thread.currentThread() == mRenderThread) {
@@ -1024,7 +1021,8 @@ public class ViewDebug {
}
if (stream != null) {
try {
- stream.write(picture);
+ picture.writeToStream(stream);
+ stream.flush();
} catch (IOException ex) {
Log.w("ViewDebug", "Aborting rendering commands capture "
+ "due to IOException writing to output stream", ex);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 67cf85cee9ac..86380a294a3d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -585,6 +585,10 @@ public final class ViewRootImpl implements ViewParent,
final Rect mWinFrame; // frame given by window manager.
final Rect mPendingBackDropFrame = new Rect();
+
+ private boolean mWillMove;
+ private boolean mWillResize;
+
boolean mPendingAlwaysConsumeSystemBars;
private final InsetsState mTempInsets = new InsetsState();
private final InsetsSourceControl[] mTempControls = new InsetsSourceControl[SIZE];
@@ -1708,6 +1712,10 @@ public final class ViewRootImpl implements ViewParent,
void notifyInsetsChanged() {
mApplyInsetsRequested = true;
+ if (mWillMove || mWillResize) {
+ // The window frame will be changed soon. The following logic will be executed then.
+ return;
+ }
requestLayout();
// See comment for View.sForceLayoutWhenInsetsChanged
@@ -2665,7 +2673,7 @@ public final class ViewRootImpl implements ViewParent,
}
}
- if (mApplyInsetsRequested) {
+ if (mApplyInsetsRequested && !(mWillMove || mWillResize)) {
dispatchApplyInsets(host);
if (mLayoutRequested) {
// Short-circuit catching a new layout request here, so
@@ -5235,16 +5243,25 @@ public final class ViewRootImpl implements ViewParent,
break;
case MSG_RESIZED:
case MSG_RESIZED_REPORT: {
+ mWillMove = false;
+ mWillResize = false;
final SomeArgs args = (SomeArgs) msg.obj;
handleResized(msg.what, args);
args.recycle();
break;
}
- case MSG_INSETS_CHANGED:
- mInsetsController.onStateChanged((InsetsState) msg.obj);
+ case MSG_INSETS_CHANGED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ mWillMove = args.argi1 == 1;
+ mWillResize = args.argi2 == 1;
+ mInsetsController.onStateChanged((InsetsState) args.arg1);
+ args.recycle();
break;
+ }
case MSG_INSETS_CONTROL_CHANGED: {
SomeArgs args = (SomeArgs) msg.obj;
+ mWillMove = args.argi1 == 1;
+ mWillResize = args.argi2 == 1;
// Deliver state change before control change, such that:
// a) When gaining control, controller can compare with server state to evaluate
@@ -5253,6 +5270,7 @@ public final class ViewRootImpl implements ViewParent,
// dispatched state as truth.
mInsetsController.onStateChanged((InsetsState) args.arg1);
mInsetsController.onControlsChanged((InsetsSourceControl[]) args.arg2);
+ args.recycle();
break;
}
case MSG_SHOW_INSETS: {
@@ -5270,6 +5288,7 @@ public final class ViewRootImpl implements ViewParent,
break;
}
case MSG_WINDOW_MOVED:
+ mWillMove = false;
if (mAdded) {
final int w = mWinFrame.width();
final int h = mWinFrame.height();
@@ -7744,6 +7763,8 @@ public final class ViewRootImpl implements ViewParent,
mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
}
setFrame(mTmpFrames.frame);
+ mWillMove = false;
+ mWillResize = false;
mInsetsController.onStateChanged(mTempInsets);
mInsetsController.onControlsChanged(mTempControls);
return relayoutResult;
@@ -8179,7 +8200,8 @@ public final class ViewRootImpl implements ViewParent,
mHandler.sendMessage(msg);
}
- private void dispatchInsetsChanged(InsetsState insetsState) {
+ private void dispatchInsetsChanged(InsetsState insetsState, boolean willMove,
+ boolean willResize) {
if (Binder.getCallingPid() == android.os.Process.myPid()) {
insetsState = new InsetsState(insetsState, true /* copySource */);
}
@@ -8190,11 +8212,15 @@ public final class ViewRootImpl implements ViewParent,
ImeTracing.getInstance().triggerClientDump("ViewRootImpl#dispatchInsetsChanged",
getInsetsController().getHost().getInputMethodManager(), null /* icProto */);
}
- mHandler.obtainMessage(MSG_INSETS_CHANGED, insetsState).sendToTarget();
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = insetsState;
+ args.argi1 = willMove ? 1 : 0;
+ args.argi2 = willResize ? 1 : 0;
+ mHandler.obtainMessage(MSG_INSETS_CHANGED, args).sendToTarget();
}
private void dispatchInsetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {
+ InsetsSourceControl[] activeControls, boolean willMove, boolean willResize) {
if (Binder.getCallingPid() == android.os.Process.myPid()) {
insetsState = new InsetsState(insetsState, true /* copySource */);
if (activeControls != null) {
@@ -8214,6 +8240,8 @@ public final class ViewRootImpl implements ViewParent,
SomeArgs args = SomeArgs.obtain();
args.arg1 = insetsState;
args.arg2 = activeControls;
+ args.argi1 = willMove ? 1 : 0;
+ args.argi2 = willResize ? 1 : 0;
mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget();
}
@@ -9560,19 +9588,20 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
- public void insetsChanged(InsetsState insetsState) {
+ public void insetsChanged(InsetsState insetsState, boolean willMove, boolean willResize) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
- viewAncestor.dispatchInsetsChanged(insetsState);
+ viewAncestor.dispatchInsetsChanged(insetsState, willMove, willResize);
}
}
@Override
public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {
+ InsetsSourceControl[] activeControls, boolean willMove, boolean willResize) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
- viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls);
+ viewAncestor.dispatchInsetsControlChanged(
+ insetsState, activeControls, willMove, willResize);
}
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index ad4ba76a17cb..aee540f466bf 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -44,8 +44,9 @@ import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.LocalLog;
import android.util.Log;
import android.util.TimeUtils;
@@ -60,7 +61,6 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -151,12 +151,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
private final LocalLog mFlushHistory;
/**
- * If the event in the buffer is of type {@link TYPE_VIEW_TEXT_CHANGED}, this value
- * indicates whether the event has composing span or not.
- */
- private final Map<AutofillId, Boolean> mLastComposingSpan = new ArrayMap<>();
-
- /**
* Binder object used to update the session state.
*/
@NonNull
@@ -352,40 +346,34 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
// 2.1 either last or current text is empty: add.
// 2.2 last event doesn't have composing span: add.
// Otherwise, merge.
-
final CharSequence text = event.getText();
final boolean textHasComposingSpan = event.getTextHasComposingSpan();
-
- if (textHasComposingSpan && !mLastComposingSpan.isEmpty()) {
- final Boolean lastEventHasComposingSpan = mLastComposingSpan.get(event.getId());
- if (lastEventHasComposingSpan != null && lastEventHasComposingSpan.booleanValue()) {
- ContentCaptureEvent lastEvent = null;
- for (int index = mEvents.size() - 1; index >= 0; index--) {
- final ContentCaptureEvent tmpEvent = mEvents.get(index);
- if (event.getId().equals(tmpEvent.getId())) {
- lastEvent = tmpEvent;
- break;
- }
+ if (textHasComposingSpan) {
+ ContentCaptureEvent lastEvent = null;
+ for (int index = mEvents.size() - 1; index >= 0; index--) {
+ final ContentCaptureEvent tmpEvent = mEvents.get(index);
+ if (event.getId().equals(tmpEvent.getId())) {
+ lastEvent = tmpEvent;
+ break;
}
- if (lastEvent != null) {
- final CharSequence lastText = lastEvent.getText();
- final boolean bothNonEmpty = !TextUtils.isEmpty(lastText)
- && !TextUtils.isEmpty(text);
- boolean equalContent = TextUtils.equals(lastText, text);
- if (equalContent) {
- addEvent = false;
- } else if (bothNonEmpty && lastEventHasComposingSpan) {
- lastEvent.mergeEvent(event);
- addEvent = false;
- }
- if (!addEvent && sVerbose) {
- Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text="
- + getSanitizedString(text));
- }
+ }
+ if (lastEvent != null && lastEvent.getTextHasComposingSpan()) {
+ final CharSequence lastText = lastEvent.getText();
+ final boolean bothNonEmpty = !TextUtils.isEmpty(lastText)
+ && !TextUtils.isEmpty(text);
+ boolean equalContent = TextUtils.equals(lastText, text);
+ if (equalContent) {
+ addEvent = false;
+ } else if (bothNonEmpty) {
+ lastEvent.mergeEvent(event);
+ addEvent = false;
+ }
+ if (!addEvent && sVerbose) {
+ Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text="
+ + getSanitizedString(text));
}
}
}
- mLastComposingSpan.put(event.getId(), textHasComposingSpan);
}
if (!mEvents.isEmpty() && eventType == TYPE_VIEW_DISAPPEARED) {
@@ -586,7 +574,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
? Collections.EMPTY_LIST
: new ArrayList<>(mEvents);
mEvents.clear();
- mLastComposingSpan.clear();
return new ParceledListSlice<>(events);
}
@@ -717,7 +704,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
// Since the same CharSequence instance may be reused in the TextView, we need to make
// a copy of its content so that its value will not be changed by subsequent updates
// in the TextView.
- final String eventText = text == null ? null : text.toString();
+ final CharSequence eventText = stringOrSpannedStringWithoutNoCopySpans(text);
final boolean textHasComposingSpan =
text instanceof Spannable && BaseInputConnection.getComposingSpanStart(
(Spannable) text) >= 0;
@@ -726,6 +713,16 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
.setAutofillId(id).setText(eventText, textHasComposingSpan)));
}
+ private CharSequence stringOrSpannedStringWithoutNoCopySpans(CharSequence source) {
+ if (source == null) {
+ return null;
+ } else if (source instanceof Spanned) {
+ return new SpannableString(source, /* ignoreNoCopySpan= */ true);
+ } else {
+ return source.toString();
+ }
+ }
+
/** Public because is also used by ViewRootImpl */
public void notifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) {
mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 25c84ba9d440..8a044fd06dd5 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -114,6 +114,7 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -812,27 +813,8 @@ public class RemoteViews implements Parcelable, Filter {
AdapterView<?> av = (AdapterView<?>) target;
// The PendingIntent template is stored in the view's tag.
OnItemClickListener listener = (parent, view, position, id) -> {
- // The view should be a frame layout
- if (view instanceof ViewGroup) {
- ViewGroup vg = (ViewGroup) view;
-
- // AdapterViews contain their children in a frame
- // so we need to go one layer deeper here.
- if (parent instanceof AdapterViewAnimator) {
- vg = (ViewGroup) vg.getChildAt(0);
- }
- if (vg == null) return;
-
- RemoteResponse response = null;
- int childCount = vg.getChildCount();
- for (int i = 0; i < childCount; i++) {
- Object tag = vg.getChildAt(i).getTag(R.id.fillInIntent);
- if (tag instanceof RemoteResponse) {
- response = (RemoteResponse) tag;
- break;
- }
- }
- if (response == null) return;
+ RemoteResponse response = findRemoteResponseTag(view);
+ if (response != null) {
response.handleViewInteraction(view, handler);
}
};
@@ -845,6 +827,28 @@ public class RemoteViews implements Parcelable, Filter {
}
}
+ @Nullable
+ private RemoteResponse findRemoteResponseTag(@Nullable View rootView) {
+ if (rootView == null) return null;
+
+ ArrayDeque<View> viewsToCheck = new ArrayDeque<>();
+ viewsToCheck.addLast(rootView);
+
+ while (!viewsToCheck.isEmpty()) {
+ View view = viewsToCheck.removeFirst();
+ Object tag = view.getTag(R.id.fillInIntent);
+ if (tag instanceof RemoteResponse) return (RemoteResponse) tag;
+ if (!(view instanceof ViewGroup)) continue;
+
+ ViewGroup viewGroup = (ViewGroup) view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ viewsToCheck.addLast(viewGroup.getChildAt(i));
+ }
+ }
+
+ return null;
+ }
+
@Override
public int getActionTag() {
return SET_PENDING_INTENT_TEMPLATE_TAG;
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index b35eb065e3fb..862829bf9b55 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -71,6 +71,9 @@ import java.util.List;
* Note that
* <a href="{@docRoot}reference/com/google/android/material/snackbar/Snackbar">Snackbars</a> are
* preferred for brief messages while the app is in the foreground.
+ * <p>
+ * Note that toasts being sent from the background are rate limited, so avoid sending such toasts
+ * in quick succession.
*
* <div class="special reference">
* <h3>Developer Guides</h3>
diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
index 9bec505c801d..ec99c95a737c 100644
--- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
+++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
@@ -17,6 +17,7 @@
package com.android.internal.app;
import android.hardware.soundtrigger.SoundTrigger;
+import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordRejectedResult;
/**
@@ -29,8 +30,11 @@ oneway interface IHotwordRecognitionStatusCallback {
* @param recognitionEvent Object containing data relating to the
* keyphrase recognition event such as keyphrase
* extras.
+ * @param result Successful detection result payload.
*/
- void onKeyphraseDetected(in SoundTrigger.KeyphraseRecognitionEvent recognitionEvent);
+ void onKeyphraseDetected(
+ in SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
+ in HotwordDetectedResult result);
/**
* Called when a generic sound trigger event is witnessed.
diff --git a/core/java/com/android/internal/graphics/palette/CelebiQuantizer.java b/core/java/com/android/internal/graphics/palette/CelebiQuantizer.java
index de6bf2044dbc..454fd00a841c 100644
--- a/core/java/com/android/internal/graphics/palette/CelebiQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/CelebiQuantizer.java
@@ -19,26 +19,32 @@ package com.android.internal.graphics.palette;
import java.util.List;
/**
- * An implementation of Celebi's WSM quantizer, or, a Kmeans quantizer that starts with centroids
- * from a Wu quantizer to ensure 100% reproducible and quality results, and has some optimizations
- * to the Kmeans algorithm.
- *
+ * An implementation of Celebi's quantization method.
* See Celebi 2011, “Improving the Performance of K-Means for Color Quantization”
+ *
+ * First, Wu's quantizer runs. The results are used as starting points for a subsequent Kmeans
+ * run. Using Wu's quantizer ensures 100% reproducible quantization results, because the starting
+ * centroids are always the same. It also ensures high quality results, Wu is a box-cutting
+ * quantization algorithm, much like medican color cut. It minimizes variance, much like Kmeans.
+ * Wu is shown to be the highest quality box-cutting quantization algorithm.
+ *
+ * Second, a Kmeans quantizer tweaked for performance is run. Celebi calls this a weighted
+ * square means quantizer, or WSMeans. Optimizations include operating on a map of image pixels
+ * rather than all image pixels, and avoiding excess color distance calculations by using a
+ * matrix and geometrical properties to know when there won't be any cluster closer to a pixel.
*/
public class CelebiQuantizer implements Quantizer {
private List<Palette.Swatch> mSwatches;
- public CelebiQuantizer() { }
+ public CelebiQuantizer() {
+ }
@Override
public void quantize(int[] pixels, int maxColors) {
- WuQuantizer wu = new WuQuantizer(pixels, maxColors);
+ WuQuantizer wu = new WuQuantizer();
wu.quantize(pixels, maxColors);
- List<Palette.Swatch> wuSwatches = wu.getQuantizedColors();
- LABCentroid labCentroidProvider = new LABCentroid();
- WSMeansQuantizer kmeans =
- new WSMeansQuantizer(WSMeansQuantizer.createStartingCentroids(labCentroidProvider,
- wuSwatches), labCentroidProvider, pixels, maxColors);
+ WSMeansQuantizer kmeans = new WSMeansQuantizer(wu.getColors(), new LABPointProvider(),
+ wu.inputPixelToCount());
kmeans.quantize(pixels, maxColors);
mSwatches = kmeans.getQuantizedColors();
}
diff --git a/core/java/com/android/internal/graphics/palette/LABCentroid.java b/core/java/com/android/internal/graphics/palette/LABPointProvider.java
index 408cf1fe9193..21a2212d6c77 100644
--- a/core/java/com/android/internal/graphics/palette/LABCentroid.java
+++ b/core/java/com/android/internal/graphics/palette/LABPointProvider.java
@@ -26,11 +26,11 @@ import android.graphics.ColorSpace;
* in L*a*b* space, also known as deltaE, is a universally accepted standard across industries
* and worldwide.
*/
-public class LABCentroid implements CentroidProvider {
+public class LABPointProvider implements PointProvider {
final ColorSpace.Connector mRgbToLab;
final ColorSpace.Connector mLabToRgb;
- public LABCentroid() {
+ public LABPointProvider() {
mRgbToLab = ColorSpace.connect(
ColorSpace.get(ColorSpace.Named.SRGB),
ColorSpace.get(ColorSpace.Named.CIE_LAB));
@@ -39,7 +39,7 @@ public class LABCentroid implements CentroidProvider {
}
@Override
- public float[] getCentroid(int color) {
+ public float[] fromInt(int color) {
float r = Color.red(color) / 255.f;
float g = Color.green(color) / 255.f;
float b = Color.blue(color) / 255.f;
@@ -49,7 +49,7 @@ public class LABCentroid implements CentroidProvider {
}
@Override
- public int getColor(float[] centroid) {
+ public int toInt(float[] centroid) {
float[] rgb = mLabToRgb.transform(centroid);
int color = Color.rgb(rgb[0], rgb[1], rgb[2]);
return color;
diff --git a/core/java/com/android/internal/graphics/palette/Mean.java b/core/java/com/android/internal/graphics/palette/Mean.java
deleted file mode 100644
index bde036349d3b..000000000000
--- a/core/java/com/android/internal/graphics/palette/Mean.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.internal.graphics.palette;
-
-import java.util.Random;
-
-/**
- * Represents a centroid in Kmeans algorithms.
- */
-public class Mean {
- public float[] center;
-
- /**
- * Constructor.
- *
- * @param upperBound maximum value of a dimension in the space Kmeans is optimizing in
- * @param random used to generate a random center
- */
- Mean(int upperBound, Random random) {
- center =
- new float[]{
- random.nextInt(upperBound + 1), random.nextInt(upperBound + 1),
- random.nextInt(upperBound + 1)
- };
- }
-
- Mean(float[] center) {
- this.center = center;
- }
-}
diff --git a/core/java/com/android/internal/graphics/palette/MeanBucket.java b/core/java/com/android/internal/graphics/palette/MeanBucket.java
deleted file mode 100644
index ae8858a8107c..000000000000
--- a/core/java/com/android/internal/graphics/palette/MeanBucket.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.internal.graphics.palette;
-
-import java.util.HashSet;
-import java.util.Set;
-
-class MeanBucket {
- float[] mTotal = {0.f, 0.f, 0.f};
- int mCount = 0;
- Set<Integer> mColors = new HashSet<>();
-
- void add(float[] colorAsDoubles, int color, int colorCount) {
- assert (colorAsDoubles.length == 3);
- mColors.add(color);
- mTotal[0] += (colorAsDoubles[0] * colorCount);
- mTotal[1] += (colorAsDoubles[1] * colorCount);
- mTotal[2] += (colorAsDoubles[2] * colorCount);
- mCount += colorCount;
- }
-
- float[] getCentroid() {
- if (mCount == 0) {
- return null;
- }
- return new float[]{mTotal[0] / mCount, mTotal[1] / mCount, mTotal[2] / mCount};
- }
-}
diff --git a/core/java/com/android/internal/graphics/palette/CentroidProvider.java b/core/java/com/android/internal/graphics/palette/PointProvider.java
index 5fcfcbab3159..017adeb3ef27 100644
--- a/core/java/com/android/internal/graphics/palette/CentroidProvider.java
+++ b/core/java/com/android/internal/graphics/palette/PointProvider.java
@@ -18,21 +18,18 @@ package com.android.internal.graphics.palette;
import android.annotation.ColorInt;
-interface CentroidProvider {
- /**
- * @return 3 dimensions representing the color
- */
- float[] getCentroid(@ColorInt int color);
+/**
+ * Interface that allows quantizers to have a plug-and-play interface for experimenting with
+ * quantization in different color spaces.
+ */
+public interface PointProvider {
+ /** Convert a color to 3 coordinates representing the color in a color space. */
+ float[] fromInt(@ColorInt int argb);
- /**
- * @param centroid 3 dimensions representing the color
- * @return 32-bit ARGB representation
- */
+ /** Convert 3 coordinates in the color space into a color */
@ColorInt
- int getColor(float[] centroid);
+ int toInt(float[] point);
- /**
- * Distance between two centroids.
- */
+ /** Find the distance between two colosrin the color space */
float distance(float[] a, float[] b);
}
diff --git a/core/java/com/android/internal/graphics/palette/QuantizerMap.java b/core/java/com/android/internal/graphics/palette/QuantizerMap.java
new file mode 100644
index 000000000000..6b60f61b91f5
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/QuantizerMap.java
@@ -0,0 +1,62 @@
+/*
+ * 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.internal.graphics.palette;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Converts a set of pixels/colors into a map with keys of unique colors, and values of the count
+ * of the unique color in the original set of pixels.
+ *
+ * This allows other quantizers to get a significant speed boost by simply running this quantizer,
+ * and then performing operations using the map, rather than for each pixel.
+ */
+public final class QuantizerMap implements Quantizer {
+ private HashMap<Integer, Integer> mColorToCount;
+ private Palette mPalette;
+
+ @Override
+ public void quantize(@NonNull int[] pixels, int colorCount) {
+ final HashMap<Integer, Integer> colorToCount = new HashMap<>();
+ for (int pixel : pixels) {
+ colorToCount.merge(pixel, 1, Integer::sum);
+ }
+ mColorToCount = colorToCount;
+
+ List<Palette.Swatch> swatches = new ArrayList<>();
+ for (Map.Entry<Integer, Integer> entry : colorToCount.entrySet()) {
+ swatches.add(new Palette.Swatch(entry.getKey(), entry.getValue()));
+ }
+ mPalette = Palette.from(swatches);
+ }
+
+ @Override
+ public List<Palette.Swatch> getQuantizedColors() {
+ return mPalette.getSwatches();
+ }
+
+ @Nullable
+ public Map<Integer, Integer> getColorToCount() {
+ return mColorToCount;
+ }
+}
diff --git a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
index 1d865c2513cf..19ed8d07394e 100644
--- a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
@@ -16,18 +16,20 @@
package com.android.internal.graphics.palette;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
-
/**
- * A color quantizer based on the Kmeans algorithm.
+ * A color quantizer based on the Kmeans algorithm. Prefer using QuantizerCelebi.
*
* This is an implementation of Kmeans based on Celebi's 2011 paper,
* "Improving the Performance of K-Means for Color Quantization". In the paper, this algorithm is
@@ -36,253 +38,237 @@ import java.util.Set;
* well as indexing colors by their count, thus minimizing the number of points to move around.
*
* Celebi's paper also stabilizes results and guarantees high quality by using starting centroids
- * from Wu's quantization algorithm. See CelebiQuantizer for more info.
+ * from Wu's quantization algorithm. See QuantizerCelebi for more info.
*/
-public class WSMeansQuantizer implements Quantizer {
- Mean[] mMeans;
- private final Map<Integer, Integer> mCountByColor = new HashMap<>();
- private final Map<Integer, Integer> mMeanIndexByColor = new HashMap<>();
- private final Set<Integer> mUniqueColors = new HashSet<>();
- private final List<Palette.Swatch> mSwatches = new ArrayList<>();
- private final CentroidProvider mCentroidProvider;
-
- public WSMeansQuantizer(
- float[][] means, CentroidProvider centroidProvider, int[] pixels, int maxColors) {
- if (pixels == null) {
- pixels = new int[]{};
- }
- mCentroidProvider = centroidProvider;
- mMeans = new Mean[maxColors];
- for (int i = 0; i < means.length; i++) {
- mMeans[i] = new Mean(means[i]);
- }
+public final class WSMeansQuantizer implements Quantizer {
+ private static final String TAG = "QuantizerWsmeans";
+ private static final boolean DEBUG = false;
+ private static final int MAX_ITERATIONS = 10;
+ // Points won't be moved to a closer cluster, if the closer cluster is within
+ // this distance. 3.0 used because L*a*b* delta E < 3 is considered imperceptible.
+ private static final float MIN_MOVEMENT_DISTANCE = 3.0f;
- if (maxColors > means.length) {
- // Always initialize Random with the same seed. Ensures the results of quantization
- // are consistent, even when random centroids are required.
- Random random = new Random(0x42688);
- int randomMeansToCreate = maxColors - means.length;
- for (int i = 0; i < randomMeansToCreate; i++) {
- mMeans[means.length + i] = new Mean(100, random);
- }
- }
+ private final PointProvider mPointProvider;
+ private @Nullable Map<Integer, Integer> mInputPixelToCount;
+ private float[][] mClusters;
+ private int[] mClusterPopulations;
+ private float[][] mPoints;
+ private int[] mPixels;
+ private int[] mClusterIndices;
+ private int[][] mIndexMatrix = {};
+ private float[][] mDistanceMatrix = {};
- for (int pixel : pixels) {
- // These are pixels from the bitmap that is being quantized.
- // Depending on the bitmap & downscaling, it may have pixels that are less than opaque
- // Ignore those pixels.
- ///
- // Note: they don't _have_ to be ignored, for example, we could instead turn them
- // opaque. Traditionally, including outside Android, quantizers ignore transparent
- // pixels, so that strategy was chosen.
- int alpha = (pixel >> 24) & 0xff;
- if (alpha < 255) {
- continue;
- }
- Integer currentCount = mCountByColor.get(pixel);
- if (currentCount == null) {
- currentCount = 0;
- mUniqueColors.add(pixel);
- }
- mCountByColor.put(pixel, currentCount + 1);
- }
- for (int color : mUniqueColors) {
- int closestMeanIndex = -1;
- double closestMeanDistance = -1;
- float[] centroid = mCentroidProvider.getCentroid(color);
- for (int i = 0; i < mMeans.length; i++) {
- double distance = mCentroidProvider.distance(centroid, mMeans[i].center);
- if (closestMeanIndex == -1 || distance < closestMeanDistance) {
- closestMeanIndex = i;
- closestMeanDistance = distance;
- }
- }
- mMeanIndexByColor.put(color, closestMeanIndex);
- }
+ private Palette mPalette;
- if (pixels.length == 0) {
- return;
+ public WSMeansQuantizer(int[] inClusters, PointProvider pointProvider,
+ @Nullable Map<Integer, Integer> inputPixelToCount) {
+ mPointProvider = pointProvider;
+
+ mClusters = new float[inClusters.length][3];
+ int index = 0;
+ for (int cluster : inClusters) {
+ float[] point = pointProvider.fromInt(cluster);
+ mClusters[index++] = point;
}
- predict(maxColors, 0);
+ mInputPixelToCount = inputPixelToCount;
}
- /** Create starting centroids for K-means from a set of colors. */
- public static float[][] createStartingCentroids(CentroidProvider centroidProvider,
- List<Palette.Swatch> swatches) {
- float[][] startingCentroids = new float[swatches.size()][];
- for (int i = 0; i < swatches.size(); i++) {
- startingCentroids[i] = centroidProvider.getCentroid(swatches.get(i).getInt());
- }
- return startingCentroids;
+ @Override
+ public List<Palette.Swatch> getQuantizedColors() {
+ return mPalette.getSwatches();
}
- /** Create random starting centroids for K-means. */
- public static float[][] randomMeans(int maxColors, int upperBound) {
- float[][] means = new float[maxColors][];
+ @Override
+ public void quantize(@NonNull int[] pixels, int maxColors) {
+ assert (pixels.length > 0);
- // Always initialize Random with the same seed. Ensures the results of quantization
- // are consistent, even when random centroids are required.
- Random random = new Random(0x42688);
+ if (mInputPixelToCount == null) {
+ QuantizerMap mapQuantizer = new QuantizerMap();
+ mapQuantizer.quantize(pixels, maxColors);
+ mInputPixelToCount = mapQuantizer.getColorToCount();
+ }
+
+ mPoints = new float[mInputPixelToCount.size()][3];
+ mPixels = new int[mInputPixelToCount.size()];
+ int index = 0;
+ for (int pixel : mInputPixelToCount.keySet()) {
+ mPixels[index] = pixel;
+ mPoints[index] = mPointProvider.fromInt(pixel);
+ index++;
+ }
+ if (mClusters.length > 0) {
+ // This implies that the constructor was provided starting clusters. If that was the
+ // case, we limit the number of clusters to the number of starting clusters and don't
+ // initialize random clusters.
+ maxColors = Math.min(maxColors, mClusters.length);
+ }
+ maxColors = Math.min(maxColors, mPoints.length);
+
+ initializeClusters(maxColors);
+ for (int i = 0; i < MAX_ITERATIONS; i++) {
+ calculateClusterDistances(maxColors);
+ if (!reassignPoints(maxColors)) {
+ break;
+ }
+ recalculateClusterCenters(maxColors);
+ }
+
+ List<Palette.Swatch> swatches = new ArrayList<>();
for (int i = 0; i < maxColors; i++) {
- means[i] = new Mean(upperBound, random).center;
+ float[] cluster = mClusters[i];
+ int colorInt = mPointProvider.toInt(cluster);
+ swatches.add(new Palette.Swatch(colorInt, mClusterPopulations[i]));
}
- return means;
+ mPalette = Palette.from(swatches);
}
- @Override
- public void quantize(int[] pixels, int maxColors) {
+ private void initializeClusters(int maxColors) {
+ boolean hadInputClusters = mClusters.length > 0;
+ if (!hadInputClusters) {
+ int additionalClustersNeeded = maxColors - mClusters.length;
+ if (DEBUG) {
+ Log.d(TAG, "have " + mClusters.length + " clusters, want " + maxColors
+ + " results, so need " + additionalClustersNeeded + " additional clusters");
+ }
- }
+ Random random = new Random(0x42688);
+ List<float[]> additionalClusters = new ArrayList<>(additionalClustersNeeded);
+ Set<Integer> clusterIndicesUsed = new HashSet<>();
+ for (int i = 0; i < additionalClustersNeeded; i++) {
+ int index = random.nextInt(mPoints.length);
+ while (clusterIndicesUsed.contains(index)
+ && clusterIndicesUsed.size() < mPoints.length) {
+ index = random.nextInt(mPoints.length);
+ }
+ clusterIndicesUsed.add(index);
+ additionalClusters.add(mPoints[index]);
+ }
- @Override
- public List<Palette.Swatch> getQuantizedColors() {
- return mSwatches;
+ float[][] newClusters = (float[][]) additionalClusters.toArray();
+ float[][] clusters = Arrays.copyOf(mClusters, maxColors);
+ System.arraycopy(newClusters, 0, clusters, clusters.length, newClusters.length);
+ mClusters = clusters;
+ }
+
+ mClusterIndices = new int[mPixels.length];
+ mClusterPopulations = new int[mPixels.length];
+ Random random = new Random(0x42688);
+ for (int i = 0; i < mPixels.length; i++) {
+ int clusterIndex = random.nextInt(maxColors);
+ mClusterIndices[i] = clusterIndex;
+ mClusterPopulations[i] = mInputPixelToCount.get(mPixels[i]);
+ }
}
- private void predict(int maxColors, int iterationsCompleted) {
- double[][] centroidDistance = new double[maxColors][maxColors];
+ void calculateClusterDistances(int maxColors) {
+ if (mDistanceMatrix.length != maxColors) {
+ mDistanceMatrix = new float[maxColors][maxColors];
+ }
+
for (int i = 0; i <= maxColors; i++) {
for (int j = i + 1; j < maxColors; j++) {
- float[] meanI = mMeans[i].center;
- float[] meanJ = mMeans[j].center;
- double distance = mCentroidProvider.distance(meanI, meanJ);
- centroidDistance[i][j] = distance;
- centroidDistance[j][i] = distance;
+ float distance = mPointProvider.distance(mClusters[i], mClusters[j]);
+ mDistanceMatrix[j][i] = distance;
+ mDistanceMatrix[i][j] = distance;
}
}
- // Construct a K×K matrix M in which row i is a permutation of
- // 1,2,…,K that represents the clusters in increasing order of
- // distance of their centers from ci;
- int[][] distanceMatrix = new int[maxColors][maxColors];
+ if (mIndexMatrix.length != maxColors) {
+ mIndexMatrix = new int[maxColors][maxColors];
+ }
+
for (int i = 0; i < maxColors; i++) {
- double[] distancesFromIToAnotherMean = centroidDistance[i];
- double[] sortedByDistanceAscending = distancesFromIToAnotherMean.clone();
- Arrays.sort(sortedByDistanceAscending);
- int[] outputRow = new int[maxColors];
+ ArrayList<Distance> distances = new ArrayList<>(maxColors);
+ for (int index = 0; index < maxColors; index++) {
+ distances.add(new Distance(index, mDistanceMatrix[i][index]));
+ }
+ distances.sort(
+ (a, b) -> Float.compare(a.getDistance(), b.getDistance()));
+
for (int j = 0; j < maxColors; j++) {
- outputRow[j] = findIndex(distancesFromIToAnotherMean, sortedByDistanceAscending[j]);
+ mIndexMatrix[i][j] = distances.get(j).getIndex();
}
- distanceMatrix[i] = outputRow;
}
+ }
+
+ boolean reassignPoints(int maxColors) {
+ boolean colorMoved = false;
+ for (int i = 0; i < mPoints.length; i++) {
+ float[] point = mPoints[i];
+ int previousClusterIndex = mClusterIndices[i];
+ float[] previousCluster = mClusters[previousClusterIndex];
+ float previousDistance = mPointProvider.distance(point, previousCluster);
- // for (i=1;i≤N′;i=i+ 1) do
- // Let Sp be the cluster that xi was assigned to in the previous
- // iteration;
- // p=m[i];
- // min_dist=prev_dist=jjxi−cpjj2;
- boolean anyColorMoved = false;
- for (int intColor : mUniqueColors) {
- float[] color = mCentroidProvider.getCentroid(intColor);
- int indexOfCurrentMean = mMeanIndexByColor.get(intColor);
- Mean currentMean = mMeans[indexOfCurrentMean];
- double minDistance = mCentroidProvider.distance(color, currentMean.center);
+ float minimumDistance = previousDistance;
+ int newClusterIndex = -1;
for (int j = 1; j < maxColors; j++) {
- int indexOfClusterFromCurrentToJ = distanceMatrix[indexOfCurrentMean][j];
- double distanceBetweenJAndCurrent =
- centroidDistance[indexOfCurrentMean][indexOfClusterFromCurrentToJ];
- if (distanceBetweenJAndCurrent >= (4 * minDistance)) {
+ int t = mIndexMatrix[previousClusterIndex][j];
+ if (mDistanceMatrix[previousClusterIndex][t] >= 4 * previousDistance) {
+ // Triangle inequality proves there's can be no closer center.
break;
}
- double distanceBetweenJAndColor = mCentroidProvider.distance(mMeans[j].center,
- color);
- if (distanceBetweenJAndColor < minDistance) {
- minDistance = distanceBetweenJAndColor;
- mMeanIndexByColor.remove(intColor);
- mMeanIndexByColor.put(intColor, j);
- anyColorMoved = true;
+ float distance = mPointProvider.distance(point, mClusters[t]);
+ if (distance < minimumDistance) {
+ minimumDistance = distance;
+ newClusterIndex = t;
}
}
- }
-
- List<MeanBucket> buckets = new ArrayList<>();
- for (int i = 0; i < maxColors; i++) {
- buckets.add(new MeanBucket());
- }
-
- for (int intColor : mUniqueColors) {
- int meanIndex = mMeanIndexByColor.get(intColor);
- MeanBucket meanBucket = buckets.get(meanIndex);
- meanBucket.add(mCentroidProvider.getCentroid(intColor), intColor,
- mCountByColor.get(intColor));
- }
-
- List<Palette.Swatch> swatches = new ArrayList<>();
- boolean done = !anyColorMoved && iterationsCompleted > 0 || iterationsCompleted >= 100;
- if (done) {
- for (int i = 0; i < buckets.size(); i++) {
- MeanBucket a = buckets.get(i);
- if (a.mCount <= 0) {
- continue;
- }
- List<MeanBucket> bucketsToMerge = new ArrayList<>();
- for (int j = i + 1; j < buckets.size(); j++) {
- MeanBucket b = buckets.get(j);
- if (b.mCount == 0) {
- continue;
- }
- float[] bCentroid = b.getCentroid();
- assert (a.mCount > 0);
- assert (a.getCentroid() != null);
-
- assert (bCentroid != null);
- if (mCentroidProvider.distance(a.getCentroid(), b.getCentroid()) < 5) {
- bucketsToMerge.add(b);
- }
- }
-
- for (MeanBucket bucketToMerge : bucketsToMerge) {
- float[] centroid = bucketToMerge.getCentroid();
- a.add(centroid, mCentroidProvider.getColor(centroid), bucketToMerge.mCount);
- buckets.remove(bucketToMerge);
+ if (newClusterIndex != -1) {
+ float distanceChange = (float)
+ Math.abs((Math.sqrt(minimumDistance) - Math.sqrt(previousDistance)));
+ if (distanceChange > MIN_MOVEMENT_DISTANCE) {
+ colorMoved = true;
+ mClusterIndices[i] = newClusterIndex;
}
}
+ }
+ return colorMoved;
+ }
- for (MeanBucket bucket : buckets) {
- float[] centroid = bucket.getCentroid();
- if (centroid == null) {
- continue;
- }
+ void recalculateClusterCenters(int maxColors) {
+ mClusterPopulations = new int[maxColors];
+ float[] aSums = new float[maxColors];
+ float[] bSums = new float[maxColors];
+ float[] cSums = new float[maxColors];
+ for (int i = 0; i < mPoints.length; i++) {
+ int clusterIndex = mClusterIndices[i];
+ float[] point = mPoints[i];
+ int pixel = mPixels[i];
+ int count = mInputPixelToCount.get(pixel);
+ mClusterPopulations[clusterIndex] += count;
+ aSums[clusterIndex] += point[0] * count;
+ bSums[clusterIndex] += point[1] * count;
+ cSums[clusterIndex] += point[2] * count;
- int rgb = mCentroidProvider.getColor(centroid);
- swatches.add(new Palette.Swatch(rgb, bucket.mCount));
- mSwatches.clear();
- mSwatches.addAll(swatches);
- }
- } else {
- List<MeanBucket> emptyBuckets = new ArrayList<>();
- for (int i = 0; i < buckets.size(); i++) {
- MeanBucket bucket = buckets.get(i);
- if ((bucket.getCentroid() == null) || (bucket.mCount == 0)) {
- emptyBuckets.add(bucket);
- for (Integer color : mUniqueColors) {
- int meanIndex = mMeanIndexByColor.get(color);
- if (meanIndex > i) {
- mMeanIndexByColor.put(color, meanIndex--);
- }
- }
- }
- }
+ }
+ for (int i = 0; i < maxColors; i++) {
+ int count = mClusterPopulations[i];
+ float aSum = aSums[i];
+ float bSum = bSums[i];
+ float cSum = cSums[i];
+ mClusters[i][0] = aSum / count;
+ mClusters[i][1] = bSum / count;
+ mClusters[i][2] = cSum / count;
+ }
+ }
- Mean[] newMeans = new Mean[buckets.size()];
- for (int i = 0; i < buckets.size(); i++) {
- float[] centroid = buckets.get(i).getCentroid();
- newMeans[i] = new Mean(centroid);
- }
+ private static class Distance {
+ private final int mIndex;
+ private final float mDistance;
- predict(buckets.size(), iterationsCompleted + 1);
+ int getIndex() {
+ return mIndex;
}
- }
+ float getDistance() {
+ return mDistance;
+ }
- private static int findIndex(double[] list, double element) {
- for (int i = 0; i < list.length; i++) {
- if (list[i] == element) {
- return i;
- }
+ Distance(int index, float distance) {
+ mIndex = index;
+ mDistance = distance;
}
- throw new IllegalArgumentException("Element not in list");
}
}
diff --git a/core/java/com/android/internal/graphics/palette/WuQuantizer.java b/core/java/com/android/internal/graphics/palette/WuQuantizer.java
index a2652ea6d5e1..1cd0d721bce4 100644
--- a/core/java/com/android/internal/graphics/palette/WuQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/WuQuantizer.java
@@ -16,431 +16,447 @@
package com.android.internal.graphics.palette;
+import static java.lang.System.arraycopy;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Color;
+
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
-// All reference Wu implementations are based on the original C code by Wu.
-// Comments on methods are the same as in the original implementation, and the comment below
-// is the original class header.
/**
- * Wu's Color Quantizer (v. 2) (see Graphics Gems vol. II, pp. 126-133) Author: Xiaolin Wu
+ * Wu's quantization algorithm is a box-cut quantizer that minimizes variance. It takes longer to
+ * run than, say, median color cut, but provides the highest quality results currently known.
+ *
+ * Prefer `QuantizerCelebi`: coupled with Kmeans, this provides the best-known results for image
+ * quantization.
*
- * <p>Algorithm: Greedy orthogonal bipartition of RGB space for variance minimization aided by
- * inclusion-exclusion tricks. For speed no nearest neighbor search is done. Slightly better
- * performance can be expected by more sophisticated but more expensive versions.
+ * Seemingly all Wu implementations are based off of one C code snippet that cites a book from 1992
+ * Graphics Gems vol. II, pp. 126-133. As a result, it is very hard to understand the mechanics of
+ * the algorithm, beyond the commentary provided in the C code. Comments on the methods of this
+ * class are avoided in favor of finding another implementation and reading the commentary there,
+ * avoiding perpetuating the same incomplete and somewhat confusing commentary here.
*/
-public class WuQuantizer implements Quantizer {
- private static final int MAX_COLORS = 256;
- private static final int RED = 2;
- private static final int GREEN = 1;
- private static final int BLUE = 0;
-
- private static final int QUANT_SIZE = 33;
- private final List<Palette.Swatch> mSwatches = new ArrayList<>();
+public final class WuQuantizer implements Quantizer {
+ // A histogram of all the input colors is constructed. It has the shape of a
+ // cube. The cube would be too large if it contained all 16 million colors:
+ // historical best practice is to use 5 bits of the 8 in each channel,
+ // reducing the histogram to a volume of ~32,000.
+ private static final int BITS = 5;
+ private static final int MAX_INDEX = 32;
+ private static final int SIDE_LENGTH = 33;
+ private static final int TOTAL_SIZE = 35937;
+
+ private int[] mWeights;
+ private int[] mMomentsR;
+ private int[] mMomentsG;
+ private int[] mMomentsB;
+ private double[] mMoments;
+ private Box[] mCubes;
+ private Palette mPalette;
+ private int[] mColors;
+ private Map<Integer, Integer> mInputPixelToCount;
@Override
public List<Palette.Swatch> getQuantizedColors() {
- return mSwatches;
+ return mPalette.getSwatches();
}
- private static final class Box {
- int mR0; /* min value, exclusive */
- int mR1; /* max value, inclusive */
- int mG0;
- int mG1;
- int mB0;
- int mB1;
- int mVol;
+ @Override
+ public void quantize(@NonNull int[] pixels, int colorCount) {
+ assert (pixels.length > 0);
+
+ QuantizerMap quantizerMap = new QuantizerMap();
+ quantizerMap.quantize(pixels, colorCount);
+ mInputPixelToCount = quantizerMap.getColorToCount();
+ // Extraction should not be run on using a color count higher than the number of colors
+ // in the pixels. The algorithm doesn't expect that to be the case, unexpected results and
+ // exceptions may occur.
+ Set<Integer> uniqueColors = mInputPixelToCount.keySet();
+ if (uniqueColors.size() <= colorCount) {
+ mColors = new int[mInputPixelToCount.keySet().size()];
+ int index = 0;
+ for (int color : uniqueColors) {
+ mColors[index++] = color;
+ }
+ } else {
+ constructHistogram(mInputPixelToCount);
+ createMoments();
+ CreateBoxesResult createBoxesResult = createBoxes(colorCount);
+ mColors = createResult(createBoxesResult.mResultCount);
+ }
+
+ List<Palette.Swatch> swatches = new ArrayList<>();
+ for (int color : mColors) {
+ swatches.add(new Palette.Swatch(color, 0));
+ }
+ mPalette = Palette.from(swatches);
}
- private final int mSize; /* image size, in bytes. */
- private int mMaxColors;
- private int[] mQadd;
- private final int[] mPixels;
+ @Nullable
+ public int[] getColors() {
+ return mColors;
+ }
- private final double[][][] mM2 = new double[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
- private final long[][][] mWt = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
- private final long[][][] mMr = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
- private final long[][][] mMg = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
- private final long[][][] mMb = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+ /** Keys are color ints, values are the number of pixels in the image matching that color int */
+ @Nullable
+ public Map<Integer, Integer> inputPixelToCount() {
+ return mInputPixelToCount;
+ }
- public WuQuantizer(int[] pixels, int maxColorCount) {
- if (pixels == null) {
- pixels = new int[]{};
- }
- this.mPixels = pixels;
- this.mSize = pixels.length;
+ private static int getIndex(int r, int g, int b) {
+ return (r << 10) + (r << 6) + (g << 5) + r + g + b;
}
- @Override
- public void quantize(int[] colors, int maxColorCount) {
- // All of the sample Wu implementations are reimplementations of a snippet of C code from
- // the early 90s. They all cap the maximum # of colors at 256, and it is impossible to tell
- // if this is a requirement, a consequence of QUANT_SIZE, or arbitrary.
- //
- // Also, the number of maximum colors should be capped at the number of pixels - otherwise,
- // If extraction is run on a set of pixels whose count is less than max colors,
- // then colors.length < max colors, and accesses to colors[index] throw an
- // ArrayOutOfBoundsException.
- this.mMaxColors = Math.min(Math.min(MAX_COLORS, maxColorCount), colors.length);
- Box[] cube = new Box[mMaxColors];
- int red, green, blue;
-
- int next, i, k;
- long weight;
- double[] vv = new double[mMaxColors];
- double temp;
-
- compute3DHistogram(mWt, mMr, mMg, mMb, mM2);
- computeMoments(mWt, mMr, mMg, mMb, mM2);
-
- for (i = 0; i < mMaxColors; i++) {
- cube[i] = new Box();
+ private void constructHistogram(Map<Integer, Integer> pixels) {
+ mWeights = new int[TOTAL_SIZE];
+ mMomentsR = new int[TOTAL_SIZE];
+ mMomentsG = new int[TOTAL_SIZE];
+ mMomentsB = new int[TOTAL_SIZE];
+ mMoments = new double[TOTAL_SIZE];
+
+ for (Map.Entry<Integer, Integer> pair : pixels.entrySet()) {
+ int pixel = pair.getKey();
+ int count = pair.getValue();
+ int red = Color.red(pixel);
+ int green = Color.green(pixel);
+ int blue = Color.blue(pixel);
+ int bitsToRemove = 8 - BITS;
+ int iR = (red >> bitsToRemove) + 1;
+ int iG = (green >> bitsToRemove) + 1;
+ int iB = (blue >> bitsToRemove) + 1;
+ int index = getIndex(iR, iG, iB);
+ mWeights[index] += count;
+ mMomentsR[index] += (red * count);
+ mMomentsG[index] += (green * count);
+ mMomentsB[index] += (blue * count);
+ mMoments[index] += (count * ((red * red) + (green * green) + (blue * blue)));
}
+ }
- cube[0].mR0 = cube[0].mG0 = cube[0].mB0 = 0;
- cube[0].mR1 = cube[0].mG1 = cube[0].mB1 = QUANT_SIZE - 1;
- next = 0;
+ private void createMoments() {
+ for (int r = 1; r < SIDE_LENGTH; ++r) {
+ int[] area = new int[SIDE_LENGTH];
+ int[] areaR = new int[SIDE_LENGTH];
+ int[] areaG = new int[SIDE_LENGTH];
+ int[] areaB = new int[SIDE_LENGTH];
+ double[] area2 = new double[SIDE_LENGTH];
+
+ for (int g = 1; g < SIDE_LENGTH; ++g) {
+ int line = 0;
+ int lineR = 0;
+ int lineG = 0;
+ int lineB = 0;
+
+ double line2 = 0.0;
+ for (int b = 1; b < SIDE_LENGTH; ++b) {
+ int index = getIndex(r, g, b);
+ line += mWeights[index];
+ lineR += mMomentsR[index];
+ lineG += mMomentsG[index];
+ lineB += mMomentsB[index];
+ line2 += mMoments[index];
+
+ area[b] += line;
+ areaR[b] += lineR;
+ areaG[b] += lineG;
+ areaB[b] += lineB;
+ area2[b] += line2;
+
+ int previousIndex = getIndex(r - 1, g, b);
+ mWeights[index] = mWeights[previousIndex] + area[b];
+ mMomentsR[index] = mMomentsR[previousIndex] + areaR[b];
+ mMomentsG[index] = mMomentsG[previousIndex] + areaG[b];
+ mMomentsB[index] = mMomentsB[previousIndex] + areaB[b];
+ mMoments[index] = mMoments[previousIndex] + area2[b];
+ }
+ }
+ }
+ }
- for (i = 1; i < mMaxColors; ++i) {
- if (cut(cube[next], cube[i])) {
- vv[next] = (cube[next].mVol > 1) ? getVariance(cube[next]) : 0.0f;
- vv[i] = (cube[i].mVol > 1) ? getVariance(cube[i]) : 0.0f;
+ private CreateBoxesResult createBoxes(int maxColorCount) {
+ mCubes = new Box[maxColorCount];
+ for (int i = 0; i < maxColorCount; i++) {
+ mCubes[i] = new Box();
+ }
+ double[] volumeVariance = new double[maxColorCount];
+ Box firstBox = mCubes[0];
+ firstBox.r1 = MAX_INDEX;
+ firstBox.g1 = MAX_INDEX;
+ firstBox.b1 = MAX_INDEX;
+
+ int generatedColorCount = 0;
+ int next = 0;
+
+ for (int i = 1; i < maxColorCount; i++) {
+ if (cut(mCubes[next], mCubes[i])) {
+ volumeVariance[next] = (mCubes[next].vol > 1) ? variance(mCubes[next]) : 0.0;
+ volumeVariance[i] = (mCubes[i].vol > 1) ? variance(mCubes[i]) : 0.0;
} else {
- vv[next] = 0.0f;
+ volumeVariance[next] = 0.0;
i--;
}
+
next = 0;
- temp = vv[0];
- for (k = 1; k <= i; ++k) {
- if (vv[k] > temp) {
- temp = vv[k];
+
+ double temp = volumeVariance[0];
+ for (int k = 1; k <= i; k++) {
+ if (volumeVariance[k] > temp) {
+ temp = volumeVariance[k];
next = k;
}
}
- if (temp <= 0.0f) {
+ generatedColorCount = i + 1;
+ if (temp <= 0.0) {
break;
}
}
- for (k = 0; k < mMaxColors; ++k) {
- weight = getVolume(cube[k], mWt);
+ return new CreateBoxesResult(maxColorCount, generatedColorCount);
+ }
+
+ private int[] createResult(int colorCount) {
+ int[] colors = new int[colorCount];
+ int nextAvailableIndex = 0;
+ for (int i = 0; i < colorCount; ++i) {
+ Box cube = mCubes[i];
+ int weight = volume(cube, mWeights);
if (weight > 0) {
- red = (int) (getVolume(cube[k], mMr) / weight);
- green = (int) (getVolume(cube[k], mMg) / weight);
- blue = (int) (getVolume(cube[k], mMb) / weight);
- colors[k] = (255 << 24) | (red << 16) | (green << 8) | blue;
- } else {
- colors[k] = 0;
+ int r = (volume(cube, mMomentsR) / weight);
+ int g = (volume(cube, mMomentsG) / weight);
+ int b = (volume(cube, mMomentsB) / weight);
+ int color = Color.rgb(r, g, b);
+ colors[nextAvailableIndex++] = color;
}
}
+ int[] resultArray = new int[nextAvailableIndex];
+ arraycopy(colors, 0, resultArray, 0, nextAvailableIndex);
+ return resultArray;
+ }
- int bitsPerPixel = 0;
- while ((1 << bitsPerPixel) < mMaxColors) {
- bitsPerPixel++;
- }
+ private double variance(Box cube) {
+ int dr = volume(cube, mMomentsR);
+ int dg = volume(cube, mMomentsG);
+ int db = volume(cube, mMomentsB);
+ double xx =
+ mMoments[getIndex(cube.r1, cube.g1, cube.b1)]
+ - mMoments[getIndex(cube.r1, cube.g1, cube.b0)]
+ - mMoments[getIndex(cube.r1, cube.g0, cube.b1)]
+ + mMoments[getIndex(cube.r1, cube.g0, cube.b0)]
+ - mMoments[getIndex(cube.r0, cube.g1, cube.b1)]
+ + mMoments[getIndex(cube.r0, cube.g1, cube.b0)]
+ + mMoments[getIndex(cube.r0, cube.g0, cube.b1)]
+ - mMoments[getIndex(cube.r0, cube.g0, cube.b0)];
+
+ int hypotenuse = (dr * dr + dg * dg + db * db);
+ int volume2 = volume(cube, mWeights);
+ double variance2 = xx - ((double) hypotenuse / (double) volume2);
+ return variance2;
+ }
- List<Palette.Swatch> swatches = new ArrayList<>();
- for (int l = 0; l < k; l++) {
- int pixel = colors[l];
- if (pixel == 0) {
- continue;
+ private boolean cut(Box one, Box two) {
+ int wholeR = volume(one, mMomentsR);
+ int wholeG = volume(one, mMomentsG);
+ int wholeB = volume(one, mMomentsB);
+ int wholeW = volume(one, mWeights);
+
+ MaximizeResult maxRResult =
+ maximize(one, Direction.RED, one.r0 + 1, one.r1, wholeR, wholeG, wholeB, wholeW);
+ MaximizeResult maxGResult =
+ maximize(one, Direction.GREEN, one.g0 + 1, one.g1, wholeR, wholeG, wholeB, wholeW);
+ MaximizeResult maxBResult =
+ maximize(one, Direction.BLUE, one.b0 + 1, one.b1, wholeR, wholeG, wholeB, wholeW);
+ Direction cutDirection;
+ double maxR = maxRResult.mMaximum;
+ double maxG = maxGResult.mMaximum;
+ double maxB = maxBResult.mMaximum;
+ if (maxR >= maxG && maxR >= maxB) {
+ if (maxRResult.mCutLocation < 0) {
+ return false;
}
- swatches.add(new Palette.Swatch(pixel, 0));
+ cutDirection = Direction.RED;
+ } else if (maxG >= maxR && maxG >= maxB) {
+ cutDirection = Direction.GREEN;
+ } else {
+ cutDirection = Direction.BLUE;
}
- mSwatches.clear();
- mSwatches.addAll(swatches);
- }
- /* Histogram is in elements 1..HISTSIZE along each axis,
- * element 0 is for base or marginal value
- * NB: these must start out 0!
- */
- private void compute3DHistogram(
- long[][][] vwt, long[][][] vmr, long[][][] vmg, long[][][] vmb, double[][][] m2) {
- // build 3-D color histogram of counts, r/g/b, and c^2
- int r, g, b;
- int i;
- int inr;
- int ing;
- int inb;
- int[] table = new int[256];
-
- for (i = 0; i < 256; i++) {
- table[i] = i * i;
+ two.r1 = one.r1;
+ two.g1 = one.g1;
+ two.b1 = one.b1;
+
+ switch (cutDirection) {
+ case RED:
+ one.r1 = maxRResult.mCutLocation;
+ two.r0 = one.r1;
+ two.g0 = one.g0;
+ two.b0 = one.b0;
+ break;
+ case GREEN:
+ one.g1 = maxGResult.mCutLocation;
+ two.r0 = one.r0;
+ two.g0 = one.g1;
+ two.b0 = one.b0;
+ break;
+ case BLUE:
+ one.b1 = maxBResult.mCutLocation;
+ two.r0 = one.r0;
+ two.g0 = one.g0;
+ two.b0 = one.b1;
+ break;
+ default:
+ throw new IllegalArgumentException("unexpected direction " + cutDirection);
}
- mQadd = new int[mSize];
+ one.vol = (one.r1 - one.r0) * (one.g1 - one.g0) * (one.b1 - one.b0);
+ two.vol = (two.r1 - two.r0) * (two.g1 - two.g0) * (two.b1 - two.b0);
- for (i = 0; i < mSize; ++i) {
- int rgb = mPixels[i];
- // Skip less than opaque pixels. They're not meaningful in the context of palette
- // generation for UI schemes.
- if ((rgb >>> 24) < 0xff) {
- continue;
- }
- r = ((rgb >> 16) & 0xff);
- g = ((rgb >> 8) & 0xff);
- b = (rgb & 0xff);
- inr = (r >> 3) + 1;
- ing = (g >> 3) + 1;
- inb = (b >> 3) + 1;
- mQadd[i] = (inr << 10) + (inr << 6) + inr + (ing << 5) + ing + inb;
- /*[inr][ing][inb]*/
- ++vwt[inr][ing][inb];
- vmr[inr][ing][inb] += r;
- vmg[inr][ing][inb] += g;
- vmb[inr][ing][inb] += b;
- m2[inr][ing][inb] += table[r] + table[g] + table[b];
- }
+ return true;
}
- /* At conclusion of the histogram step, we can interpret
- * wt[r][g][b] = sum over voxel of P(c)
- * mr[r][g][b] = sum over voxel of r*P(c) , similarly for mg, mb
- * m2[r][g][b] = sum over voxel of c^2*P(c)
- * Actually each of these should be divided by 'size' to give the usual
- * interpretation of P() as ranging from 0 to 1, but we needn't do that here.
- *
- * We now convert histogram into moments so that we can rapidly calculate
- * the sums of the above quantities over any desired box.
- */
- private void computeMoments(
- long[][][] vwt, long[][][] vmr, long[][][] vmg, long[][][] vmb, double[][][] m2) {
- /* compute cumulative moments. */
- int i, r, g, b;
- int line, line_r, line_g, line_b;
- int[] area = new int[QUANT_SIZE];
- int[] area_r = new int[QUANT_SIZE];
- int[] area_g = new int[QUANT_SIZE];
- int[] area_b = new int[QUANT_SIZE];
- double line2;
- double[] area2 = new double[QUANT_SIZE];
-
- for (r = 1; r < QUANT_SIZE; ++r) {
- for (i = 0; i < QUANT_SIZE; ++i) {
- area2[i] = area[i] = area_r[i] = area_g[i] = area_b[i] = 0;
+ private MaximizeResult maximize(
+ Box cube,
+ Direction direction,
+ int first,
+ int last,
+ int wholeR,
+ int wholeG,
+ int wholeB,
+ int wholeW) {
+ int baseR = bottom(cube, direction, mMomentsR);
+ int baseG = bottom(cube, direction, mMomentsG);
+ int baseB = bottom(cube, direction, mMomentsB);
+ int baseW = bottom(cube, direction, mWeights);
+
+ double max = 0.0;
+ int cut = -1;
+ for (int i = first; i < last; i++) {
+ int halfR = baseR + top(cube, direction, i, mMomentsR);
+ int halfG = baseG + top(cube, direction, i, mMomentsG);
+ int halfB = baseB + top(cube, direction, i, mMomentsB);
+ int halfW = baseW + top(cube, direction, i, mWeights);
+
+ if (halfW == 0) {
+ continue;
+ }
+ double tempNumerator = halfR * halfR + halfG * halfG + halfB * halfB;
+ double tempDenominator = halfW;
+ double temp = tempNumerator / tempDenominator;
+
+ halfR = wholeR - halfR;
+ halfG = wholeG - halfG;
+ halfB = wholeB - halfB;
+ halfW = wholeW - halfW;
+ if (halfW == 0) {
+ continue;
}
- for (g = 1; g < QUANT_SIZE; ++g) {
- line2 = line = line_r = line_g = line_b = 0;
- for (b = 1; b < QUANT_SIZE; ++b) {
- line += vwt[r][g][b];
- line_r += vmr[r][g][b];
- line_g += vmg[r][g][b];
- line_b += vmb[r][g][b];
- line2 += m2[r][g][b];
-
- area[b] += line;
- area_r[b] += line_r;
- area_g[b] += line_g;
- area_b[b] += line_b;
- area2[b] += line2;
- vwt[r][g][b] = vwt[r - 1][g][b] + area[b];
- vmr[r][g][b] = vmr[r - 1][g][b] + area_r[b];
- vmg[r][g][b] = vmg[r - 1][g][b] + area_g[b];
- vmb[r][g][b] = vmb[r - 1][g][b] + area_b[b];
- m2[r][g][b] = m2[r - 1][g][b] + area2[b];
- }
+ tempNumerator = halfR * halfR + halfG * halfG + halfB * halfB;
+ tempDenominator = halfW;
+ temp += (tempNumerator / tempDenominator);
+ if (temp > max) {
+ max = temp;
+ cut = i;
}
}
+ return new MaximizeResult(cut, max);
}
- private long getVolume(Box cube, long[][][] mmt) {
- /* Compute sum over a box of any given statistic */
- return (mmt[cube.mR1][cube.mG1][cube.mB1]
- - mmt[cube.mR1][cube.mG1][cube.mB0]
- - mmt[cube.mR1][cube.mG0][cube.mB1]
- + mmt[cube.mR1][cube.mG0][cube.mB0]
- - mmt[cube.mR0][cube.mG1][cube.mB1]
- + mmt[cube.mR0][cube.mG1][cube.mB0]
- + mmt[cube.mR0][cube.mG0][cube.mB1]
- - mmt[cube.mR0][cube.mG0][cube.mB0]);
+ private static int volume(Box cube, int[] moment) {
+ return (moment[getIndex(cube.r1, cube.g1, cube.b1)]
+ - moment[getIndex(cube.r1, cube.g1, cube.b0)]
+ - moment[getIndex(cube.r1, cube.g0, cube.b1)]
+ + moment[getIndex(cube.r1, cube.g0, cube.b0)]
+ - moment[getIndex(cube.r0, cube.g1, cube.b1)]
+ + moment[getIndex(cube.r0, cube.g1, cube.b0)]
+ + moment[getIndex(cube.r0, cube.g0, cube.b1)]
+ - moment[getIndex(cube.r0, cube.g0, cube.b0)]);
}
- /* The next two routines allow a slightly more efficient calculation
- * of Vol() for a proposed subbox of a given box. The sum of Top()
- * and Bottom() is the Vol() of a subbox split in the given direction
- * and with the specified new upper bound.
- */
- private long getBottom(Box cube, int dir, long[][][] mmt) {
- /* Compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1 */
- /* (depending on dir) */
- switch (dir) {
+ private static int bottom(Box cube, Direction direction, int[] moment) {
+ switch (direction) {
case RED:
- return (-mmt[cube.mR0][cube.mG1][cube.mB1]
- + mmt[cube.mR0][cube.mG1][cube.mB0]
- + mmt[cube.mR0][cube.mG0][cube.mB1]
- - mmt[cube.mR0][cube.mG0][cube.mB0]);
+ return -moment[getIndex(cube.r0, cube.g1, cube.b1)]
+ + moment[getIndex(cube.r0, cube.g1, cube.b0)]
+ + moment[getIndex(cube.r0, cube.g0, cube.b1)]
+ - moment[getIndex(cube.r0, cube.g0, cube.b0)];
case GREEN:
- return (-mmt[cube.mR1][cube.mG0][cube.mB1]
- + mmt[cube.mR1][cube.mG0][cube.mB0]
- + mmt[cube.mR0][cube.mG0][cube.mB1]
- - mmt[cube.mR0][cube.mG0][cube.mB0]);
+ return -moment[getIndex(cube.r1, cube.g0, cube.b1)]
+ + moment[getIndex(cube.r1, cube.g0, cube.b0)]
+ + moment[getIndex(cube.r0, cube.g0, cube.b1)]
+ - moment[getIndex(cube.r0, cube.g0, cube.b0)];
case BLUE:
- return (-mmt[cube.mR1][cube.mG1][cube.mB0]
- + mmt[cube.mR1][cube.mG0][cube.mB0]
- + mmt[cube.mR0][cube.mG1][cube.mB0]
- - mmt[cube.mR0][cube.mG0][cube.mB0]);
+ return -moment[getIndex(cube.r1, cube.g1, cube.b0)]
+ + moment[getIndex(cube.r1, cube.g0, cube.b0)]
+ + moment[getIndex(cube.r0, cube.g1, cube.b0)]
+ - moment[getIndex(cube.r0, cube.g0, cube.b0)];
default:
- return 0;
+ throw new IllegalArgumentException("unexpected direction " + direction);
}
}
- private long getTop(Box cube, int dir, int pos, long[][][] mmt) {
- /* Compute remainder of Vol(cube, mmt), substituting pos for */
- /* r1, g1, or b1 (depending on dir) */
- switch (dir) {
+ private static int top(Box cube, Direction direction, int position, int[] moment) {
+ switch (direction) {
case RED:
- return (mmt[pos][cube.mG1][cube.mB1]
- - mmt[pos][cube.mG1][cube.mB0]
- - mmt[pos][cube.mG0][cube.mB1]
- + mmt[pos][cube.mG0][cube.mB0]);
+ return (moment[getIndex(position, cube.g1, cube.b1)]
+ - moment[getIndex(position, cube.g1, cube.b0)]
+ - moment[getIndex(position, cube.g0, cube.b1)]
+ + moment[getIndex(position, cube.g0, cube.b0)]);
case GREEN:
- return (mmt[cube.mR1][pos][cube.mB1]
- - mmt[cube.mR1][pos][cube.mB0]
- - mmt[cube.mR0][pos][cube.mB1]
- + mmt[cube.mR0][pos][cube.mB0]);
+ return (moment[getIndex(cube.r1, position, cube.b1)]
+ - moment[getIndex(cube.r1, position, cube.b0)]
+ - moment[getIndex(cube.r0, position, cube.b1)]
+ + moment[getIndex(cube.r0, position, cube.b0)]);
case BLUE:
- return (mmt[cube.mR1][cube.mG1][pos]
- - mmt[cube.mR1][cube.mG0][pos]
- - mmt[cube.mR0][cube.mG1][pos]
- + mmt[cube.mR0][cube.mG0][pos]);
+ return (moment[getIndex(cube.r1, cube.g1, position)]
+ - moment[getIndex(cube.r1, cube.g0, position)]
+ - moment[getIndex(cube.r0, cube.g1, position)]
+ + moment[getIndex(cube.r0, cube.g0, position)]);
default:
- return 0;
+ throw new IllegalArgumentException("unexpected direction " + direction);
}
}
- private double getVariance(Box cube) {
- /* Compute the weighted variance of a box */
- /* NB: as with the raw statistics, this is really the variance * size */
- double dr, dg, db, xx;
- dr = getVolume(cube, mMr);
- dg = getVolume(cube, mMg);
- db = getVolume(cube, mMb);
- xx =
- mM2[cube.mR1][cube.mG1][cube.mB1]
- - mM2[cube.mR1][cube.mG1][cube.mB0]
- - mM2[cube.mR1][cube.mG0][cube.mB1]
- + mM2[cube.mR1][cube.mG0][cube.mB0]
- - mM2[cube.mR0][cube.mG1][cube.mB1]
- + mM2[cube.mR0][cube.mG1][cube.mB0]
- + mM2[cube.mR0][cube.mG0][cube.mB1]
- - mM2[cube.mR0][cube.mG0][cube.mB0];
- return xx - (dr * dr + dg * dg + db * db) / getVolume(cube, mWt);
+ private enum Direction {
+ RED,
+ GREEN,
+ BLUE
}
- /* We want to minimize the sum of the variances of two subboxes.
- * The sum(c^2) terms can be ignored since their sum over both subboxes
- * is the same (the sum for the whole box) no matter where we split.
- * The remaining terms have a minus sign in the variance formula,
- * so we drop the minus sign and MAXIMIZE the sum of the two terms.
- */
- private double maximize(
- Box cube,
- int dir,
- int first,
- int last,
- int[] cut,
- long wholeR,
- long wholeG,
- long wholeB,
- long wholeW) {
- long half_r, half_g, half_b, half_w;
- long base_r, base_g, base_b, base_w;
- int i;
- double temp, max;
-
- base_r = getBottom(cube, dir, mMr);
- base_g = getBottom(cube, dir, mMg);
- base_b = getBottom(cube, dir, mMb);
- base_w = getBottom(cube, dir, mWt);
-
- max = 0.0f;
- cut[0] = -1;
-
- for (i = first; i < last; ++i) {
- half_r = base_r + getTop(cube, dir, i, mMr);
- half_g = base_g + getTop(cube, dir, i, mMg);
- half_b = base_b + getTop(cube, dir, i, mMb);
- half_w = base_w + getTop(cube, dir, i, mWt);
- /* now half_x is sum over lower half of box, if split at i */
- if (half_w == 0) /* subbox could be empty of pixels! */ {
- continue; /* never split into an empty box */
- }
- temp = (half_r * half_r + half_g * half_g + half_b * half_b) / (double) half_w;
- half_r = wholeR - half_r;
- half_g = wholeG - half_g;
- half_b = wholeB - half_b;
- half_w = wholeW - half_w;
- if (half_w == 0) /* subbox could be empty of pixels! */ {
- continue; /* never split into an empty box */
- }
- temp += (half_r * half_r + half_g * half_g + half_b * half_b) / (double) half_w;
+ private static class MaximizeResult {
+ // < 0 if cut impossible
+ final int mCutLocation;
+ final double mMaximum;
- if (temp > max) {
- max = temp;
- cut[0] = i;
- }
+ MaximizeResult(int cut, double max) {
+ mCutLocation = cut;
+ mMaximum = max;
}
-
- return max;
}
- private boolean cut(Box set1, Box set2) {
- int dir;
- int[] cutr = new int[1];
- int[] cutg = new int[1];
- int[] cutb = new int[1];
- double maxr, maxg, maxb;
- long whole_r, whole_g, whole_b, whole_w;
-
- whole_r = getVolume(set1, mMr);
- whole_g = getVolume(set1, mMg);
- whole_b = getVolume(set1, mMb);
- whole_w = getVolume(set1, mWt);
-
- maxr = maximize(set1, RED, set1.mR0 + 1, set1.mR1, cutr, whole_r, whole_g, whole_b,
- whole_w);
- maxg = maximize(set1, GREEN, set1.mG0 + 1, set1.mG1, cutg, whole_r, whole_g, whole_b,
- whole_w);
- maxb = maximize(set1, BLUE, set1.mB0 + 1, set1.mB1, cutb, whole_r, whole_g, whole_b,
- whole_w);
-
- if (maxr >= maxg && maxr >= maxb) {
- dir = RED;
- if (cutr[0] < 0) return false; /* can't split the box */
- } else if (maxg >= maxr && maxg >= maxb) {
- dir = GREEN;
- } else {
- dir = BLUE;
- }
-
- set2.mR1 = set1.mR1;
- set2.mG1 = set1.mG1;
- set2.mB1 = set1.mB1;
+ private static class CreateBoxesResult {
+ final int mRequestedCount;
+ final int mResultCount;
- switch (dir) {
- case RED:
- set2.mR0 = set1.mR1 = cutr[0];
- set2.mG0 = set1.mG0;
- set2.mB0 = set1.mB0;
- break;
- case GREEN:
- set2.mG0 = set1.mG1 = cutg[0];
- set2.mR0 = set1.mR0;
- set2.mB0 = set1.mB0;
- break;
- case BLUE:
- set2.mB0 = set1.mB1 = cutb[0];
- set2.mR0 = set1.mR0;
- set2.mG0 = set1.mG0;
- break;
+ CreateBoxesResult(int requestedCount, int resultCount) {
+ mRequestedCount = requestedCount;
+ mResultCount = resultCount;
}
- set1.mVol = (set1.mR1 - set1.mR0) * (set1.mG1 - set1.mG0) * (set1.mB1 - set1.mB0);
- set2.mVol = (set2.mR1 - set2.mR0) * (set2.mG1 - set2.mG0) * (set2.mB1 - set2.mB0);
+ }
- return true;
+ private static class Box {
+ public int r0 = 0;
+ public int r1 = 0;
+ public int g0 = 0;
+ public int g1 = 0;
+ public int b0 = 0;
+ public int b1 = 0;
+ public int vol = 0;
}
}
+
+
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 47341cd154d7..f212fc7d1228 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -66,12 +66,12 @@ public class BaseIWindow extends IWindow.Stub {
}
@Override
- public void insetsChanged(InsetsState insetsState) {
+ public void insetsChanged(InsetsState insetsState, boolean willMove, boolean willResize) {
}
@Override
public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {
+ InsetsSourceControl[] activeControls, boolean willMove, boolean willResize) {
}
@Override
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 56814c7eb774..5ca4ec0aae13 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2383,7 +2383,7 @@ android_media_AudioSystem_setSurroundFormatEnabled(JNIEnv *env, jobject thiz,
}
static jint android_media_AudioSystem_getMaxChannelCount(JNIEnv *env, jobject thiz) {
- return FCC_8;
+ return FCC_LIMIT;
}
static jint android_media_AudioSystem_getMaxSampleRate(JNIEnv *env, jobject thiz) {
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index ce847e8f70c5..73e7d86e8279 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1244,10 +1244,14 @@ static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
}
-static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
+static void NativeThemeDestroy(jlong theme_ptr) {
delete reinterpret_cast<Theme*>(theme_ptr);
}
+static jlong NativeGetThemeFreeFunction(JNIEnv* /*env*/, jclass /*clazz*/) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&NativeThemeDestroy));
+}
+
static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
jint resid, jboolean force) {
// AssetManager is accessed via the theme, so grab an explicit lock here.
@@ -1264,6 +1268,38 @@ static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlon
// jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
}
+static void NativeThemeRebase(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
+ jintArray style_ids, jbooleanArray force,
+ jint style_count) {
+ // Lock both the original asset manager of the theme and the new asset manager to be used for the
+ // theme.
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+
+ uint32_t* style_id_args = nullptr;
+ if (style_ids != nullptr) {
+ CHECK(style_count <= env->GetArrayLength(style_ids));
+ style_id_args = reinterpret_cast<uint32_t*>(env->GetPrimitiveArrayCritical(style_ids, nullptr));
+ if (style_id_args == nullptr) {
+ return;
+ }
+ }
+
+ jboolean* force_args = nullptr;
+ if (force != nullptr) {
+ CHECK(style_count <= env->GetArrayLength(force));
+ force_args = reinterpret_cast<jboolean*>(env->GetPrimitiveArrayCritical(force, nullptr));
+ if (force_args == nullptr) {
+ env->ReleasePrimitiveArrayCritical(style_ids, style_id_args, JNI_ABORT);
+ return;
+ }
+ }
+
+ auto theme = reinterpret_cast<Theme*>(theme_ptr);
+ theme->Rebase(&(*assetmanager), style_id_args, force_args, static_cast<size_t>(style_count));
+ env->ReleasePrimitiveArrayCritical(style_ids, style_id_args, JNI_ABORT);
+ env->ReleasePrimitiveArrayCritical(force, force_args, JNI_ABORT);
+}
+
static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
@@ -1284,10 +1320,6 @@ static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manag
}
}
-static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
- reinterpret_cast<Theme*>(theme_ptr)->Clear();
-}
-
static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
jint resid, jobject typed_value,
jboolean resolve_references) {
@@ -1446,10 +1478,11 @@ static const JNINativeMethod gAssetManagerMethods[] = {
// Theme related methods.
{"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
- {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
+ {"nativeGetThemeFreeFunction", "()J", (void*)NativeGetThemeFreeFunction},
{"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
+ {"nativeThemeRebase", "(JJ[I[ZI)V", (void*)NativeThemeRebase},
+
{"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
- {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
{"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
(void*)NativeThemeGetAttributeValue},
{"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6b6cbea94009..50a242cab481 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1408,13 +1408,13 @@
<!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
system only camera devices.
- <p>Protection level: system|signature
+ <p>Protection level: system|signature|role
@hide -->
<permission android:name="android.permission.SYSTEM_CAMERA"
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_systemCamera"
android:description="@string/permdesc_systemCamera"
- android:protectionLevel="system|signature" />
+ android:protectionLevel="system|signature|role" />
<!-- @SystemApi Allows receiving the camera service notifications when a camera is opened
(by a certain application package) or closed.
diff --git a/core/res/res/drawable-car/car_checkbox.xml b/core/res/res/drawable-car/car_checkbox.xml
index 651e6786c460..083a7aa193aa 100644
--- a/core/res/res/drawable-car/car_checkbox.xml
+++ b/core/res/res/drawable-car/car_checkbox.xml
@@ -20,4 +20,8 @@
android:width="@*android:dimen/car_primary_icon_size"
android:height="@*android:dimen/car_primary_icon_size"
android:drawable="@drawable/btn_check_material_anim"/>
+ <item
+ android:width="@*android:dimen/car_primary_icon_size"
+ android:height="@*android:dimen/car_primary_icon_size"
+ android:drawable="@drawable/car_checkbox_background"/>
</layer-list>
diff --git a/core/res/res/drawable-car/car_checkbox_background.xml b/core/res/res/drawable-car/car_checkbox_background.xml
new file mode 100644
index 000000000000..69dcdbb0e94c
--- /dev/null
+++ b/core/res/res/drawable-car/car_checkbox_background.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:state_pressed="true">
+ <shape android:shape="rectangle">
+ <solid android:color="#8A0041BE" />
+ <stroke android:width="4dp" android:color="#0041BE" />
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="#3D0059B3" />
+ <stroke android:width="8dp" android:color="#0059B3" />
+ </shape>
+ </item>
+</selector>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 77d3e6066100..09d6266e42b2 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1961,7 +1961,7 @@
<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_title" msgid="7080620065745260137">"هل تريد تفعيل ميزة \"توفير البيانات\"؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"تفعيل"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="zero">‏لمدة أقل من دقيقة (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -2201,8 +2201,8 @@
<string name="harmful_app_warning_title" msgid="8794823880881113856">"تم العثور على تطبيق ضار"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"يريد تطبيق <xliff:g id="APP_0">%1$s</xliff:g> عرض شرائح تطبيق <xliff:g id="APP_2">%2$s</xliff:g>."</string>
<string name="screenshot_edit" msgid="7408934887203689207">"تعديل"</string>
- <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"سيهتز الهاتف عند تلقّي المكالمات والإشعارات"</string>
- <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"سيتم كتم صوت الهاتف عند تلقي المكالمات والإشعارات"</string>
+ <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"سيهتز الهاتف عند تلقّي المكالمات والإشعارات."</string>
+ <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"سيتم كتم صوت الهاتف عند تلقي المكالمات والإشعارات."</string>
<string name="notification_channel_system_changes" msgid="2462010596920209678">"تغييرات النظام"</string>
<string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"عدم الإزعاج"</string>
<string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"جديد: يؤدي تفعيل ميزة \"عدم الإزعاج\" إلى إخفاء الإشعارات."</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 79043149b907..8301144fb9d3 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1564,7 +1564,7 @@
<string name="description_target_unlock_tablet" msgid="7431571180065859551">"Kilidi açmaq üçün vurun."</string>
<string name="action_bar_home_description" msgid="1501655419158631974">"Evə naviqasiya et"</string>
<string name="action_bar_up_description" msgid="6611579697195026932">"Yuxarı gedin"</string>
- <string name="action_menu_overflow_description" msgid="4579536843510088170">"Digər variantlar"</string>
+ <string name="action_menu_overflow_description" msgid="4579536843510088170">"Digər seçimlər"</string>
<string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
<string name="storage_internal" msgid="8490227947584914460">"Daxili paylaşılan yaddaş"</string>
@@ -1711,11 +1711,11 @@
<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="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Əlavə qaraltma"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Əlavə tündləşmə"</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>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> istifadə etmək üçün hər iki səs düyməsini üç saniyə basıb saxlayın"</string>
- <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Əlçatımlılıq düyməsinə toxunduqda istifadə edəcəyiniz funksiyanı seçin:"</string>
+ <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Xüsusi imkanlar düyməsinə toxunanda istədiyiniz funksiyanı seçin:"</string>
<string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Əlçatımlılıq jesti (iki barmağınızla ekranın aşağısından yuxarı doğru sürüşdürün) ilə istifadə edəcəyiniz funksiyanı seçin:"</string>
<string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Əlçatımlılıq jesti (üç barmağınızla ekranın aşağısından yuxarı doğru sürüşdürün) ilə istifadə edəcəyiniz funksiyanı seçin:"</string>
<string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Funksiyalar arasında keçid etmək üçün əlçatımlılıq düyməsinə toxunub saxlayın."</string>
@@ -1937,7 +1937,7 @@
<string name="usb_midi_peripheral_name" msgid="490523464968655741">"Android USB Peripheral Port"</string>
<string name="usb_midi_peripheral_manufacturer_name" msgid="7557148557088787741">"Android"</string>
<string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"USB Peripheral Port"</string>
- <string name="floating_toolbar_open_overflow_description" msgid="2260297653578167367">"Daha çox seçim"</string>
+ <string name="floating_toolbar_open_overflow_description" msgid="2260297653578167367">"Digər seçimlər"</string>
<string name="floating_toolbar_close_overflow_description" msgid="3949818077708138098">"Yüklənməni qapadın"</string>
<string name="maximize_button_text" msgid="4258922519914732645">"Böyüdün"</string>
<string name="close_button_text" msgid="10603510034455258">"Qapadın"</string>
@@ -2005,7 +2005,7 @@
<string name="app_category_productivity" msgid="1844422703029557883">"Məhsuldarlıq"</string>
<string name="app_category_accessibility" msgid="6643521607848547683">"Əlçatımlılıq"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Cihaz yaddaşı"</string>
- <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB sazlama"</string>
+ <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ilə sazlama"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"saat"</string>
<string name="time_picker_minute_label" msgid="8307452311269824553">"dəqiqə"</string>
<string name="time_picker_header_text" msgid="9073802285051516688">"Vaxtı ayarlayın"</string>
@@ -2277,7 +2277,7 @@
<string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
<string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
<string name="window_magnification_prompt_title" msgid="2876703640772778215">"Yeni böyütmə ayarları"</string>
- <string name="window_magnification_prompt_content" msgid="8159173903032344891">"İndi ekranınızın bir hissəsini böyüdə bilərsiniz"</string>
+ <string name="window_magnification_prompt_content" msgid="8159173903032344891">"İndi ekran hissəsini böyütmək olar"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Ayarlarda aktiv edin"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Qapadın"</string>
<string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"Cihaz mikrofonunu blokdan çıxarın"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4099ccbb2f62..1dadb14a145b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1869,7 +1869,7 @@
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals, determinades funcions i algunes connexions a la xarxa."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals, determinades funcions i algunes connexions a la xarxa."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"Activar l\'Economitzador de dades?"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"Vols activar l\'Economitzador de dades?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activa"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="other">Durant %1$d minuts (fins a les <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 6dbf7d4d1afe..718fe0f385db 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2225,7 +2225,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Tento obsah nelze sdílet pomocí osobních aplikací"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Tento obsah nelze otevřít pomocí osobních aplikací"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Pracovní profil je pozastaven"</string>
- <string name="resolver_switch_on_work" msgid="463709043650610420">"Klepnutím zapnete"</string>
+ <string name="resolver_switch_on_work" msgid="463709043650610420">"Klepnutím ho zapnete"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Žádné pracovní aplikace"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Žádné osobní aplikace"</string>
<string name="miniresolver_open_in_personal" msgid="2937599899213467617">"Otevřít v aplikaci <xliff:g id="APP">%s</xliff:g> v osobním profilu?"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index a67033fec66e..392973c5cfc9 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -350,7 +350,7 @@
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"Benachrichtigungen auf einem gesperrten Gerät als Vollbildaktivitäten anzeigen"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Ermöglicht der App, Benachrichtigungen auf einem gesperrten Gerät als Vollbildaktivitäten anzuzeigen"</string>
<string name="permlab_install_shortcut" msgid="7451554307502256221">"Verknüpfungen installieren"</string>
- <string name="permdesc_install_shortcut" msgid="4476328467240212503">"Ermöglicht einer App das Hinzufügen von Verknüpfungen zum Startbildschirm ohne Eingriff des Nutzers"</string>
+ <string name="permdesc_install_shortcut" msgid="4476328467240212503">"ohne Zutun des Nutzers Verknüpfungen zum Startbildschirm hinzufügen."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"Verknüpfungen deinstallieren"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Ermöglicht einer App das Entfernen von Verknüpfungen vom Startbildschirm ohne Eingriff des Nutzers"</string>
<string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"Ausgehende Anrufe umleiten"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 1b6d3d0dd5bd..0c5de09f514f 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -148,7 +148,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Solo Wi-Fi"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"Llamadas de reserva de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"Alternativa para llamadas de <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> transcurridos <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d9157831fc2b..d0bdd6fe1bc2 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -609,10 +609,10 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Hatz-markaren ikonoa"</string>
- <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Aurpegiaren bidez desblokeatzeko eginbidea"</string>
+ <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Aurpegi bidez desblokeatzeko eginbidea"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Erregistratu aurpegia berriro"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Ezagutzea hobetzeko, erregistratu aurpegia berriro"</string>
- <string name="face_setup_notification_title" msgid="8843461561970741790">"Konfiguratu aurpegiaren bidez desblokeatzeko eginbidea"</string>
+ <string name="face_setup_notification_title" msgid="8843461561970741790">"Konfiguratu aurpegi bidez desblokeatzeko eginbidea"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Telefonoa desblokeatzeko, begira iezaiozu"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Konfiguratu telefonoa desblokeatzeko modu gehiago"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Sakatu hau hatz-marka bat gehitzeko"</string>
@@ -642,16 +642,16 @@
<string name="face_error_timeout" msgid="2598544068593889762">"Saiatu berriro aurpegiaren bidez desblokeatzen"</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Ezin dira gorde aurpegiaren datu berriak. Ezabatu zaharrak."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Utzi da aurpegiaren bidezko eragiketa."</string>
- <string name="face_error_user_canceled" msgid="5766472033202928373">"Erabiltzaileak aurpegiaren bidez desblokeatzeko aukera utzi du"</string>
+ <string name="face_error_user_canceled" msgid="5766472033202928373">"Erabiltzaileak aurpegi bidez desblokeatzeko aukera utzi du"</string>
<string name="face_error_lockout" msgid="7864408714994529437">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
- <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Saiakera gehiegi egin dira. Desgaitu egin da aurpegiaren bidez desblokeatzeko eginbidea."</string>
+ <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Saiakera gehiegi egin dira. Desgaitu egin da aurpegi bidez desblokeatzeko eginbidea."</string>
<string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Saiakera gehiegi egin dira. Horren ordez, erabili pantailaren blokeoa."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Ezin da egiaztatu aurpegia. Saiatu berriro."</string>
- <string name="face_error_not_enrolled" msgid="1134739108536328412">"Ez duzu konfiguratu aurpegiaren bidez desblokeatzeko eginbidea"</string>
- <string name="face_error_hw_not_present" msgid="7940978724978763011">"Aurpegiaren bidez desblokeatzeko eginbidea ez da bateragarria gailu honekin"</string>
+ <string name="face_error_not_enrolled" msgid="1134739108536328412">"Ez duzu konfiguratu aurpegi bidez desblokeatzeko eginbidea"</string>
+ <string name="face_error_hw_not_present" msgid="7940978724978763011">"Aurpegi bidez desblokeatzeko eginbidea ez da bateragarria gailu honekin"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sentsorea aldi baterako desgaitu da."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> aurpegia"</string>
- <string name="face_app_setting_name" msgid="5854024256907828015">"Erabili aurpegiaren bidez desblokeatzeko eginbidea"</string>
+ <string name="face_app_setting_name" msgid="5854024256907828015">"Erabili aurpegi bidez desblokeatzeko eginbidea"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Erabili aurpegia edo pantailaren blokeoa"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Aurrera egiteko, erabili aurpegia"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aurrera egiteko, erabili aurpegia edo pantailaren blokeoa"</string>
@@ -884,7 +884,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Saiatu berriro"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Saiatu berriro"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Desblokeatu eginbide eta datu guztiak erabiltzeko"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Gainditu da aurpegiaren bidez desblokeatzeko saiakera-muga"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Gainditu da aurpegi bidez desblokeatzeko saiakera-muga"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"Ez dago SIM txartelik"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"Ez dago SIM txartelik tabletan."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"Ez dago SIM txartelik Android TV gailuan."</string>
@@ -954,7 +954,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Zabaldu desblokeatzeko eremua."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Hatza lerratuta desblokeatzea."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Ereduaren bidez desblokeatzea."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Aurpegiaren bidez desblokeatzeko eginbidea."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Aurpegi bidez desblokeatzeko eginbidea."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN kodearen bidez desblokeatzea."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIMa desblokeatzeko PINa."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM txartela desblokeatzeko PUK kodea."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index c1c0349817e7..ac6cca83a330 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1355,7 +1355,7 @@
<string name="no_permissions" msgid="5729199278862516390">"Lupia ei tarvita"</string>
<string name="perm_costs_money" msgid="749054595022779685">"tämä voi maksaa"</string>
<string name="dlg_ok" msgid="5103447663504839312">"OK"</string>
- <string name="usb_charging_notification_title" msgid="1674124518282666955">"Laitetta ladataan USB-yhteyden kautta"</string>
+ <string name="usb_charging_notification_title" msgid="1674124518282666955">"Laite lataa USB-yhteydellä"</string>
<string name="usb_supplying_notification_title" msgid="5378546632408101811">"Ladataan yhdistettyä laitetta USB:n kautta"</string>
<string name="usb_mtp_notification_title" msgid="1065989144124499810">"USB-tiedostonsiirto on käytössä"</string>
<string name="usb_ptp_notification_title" msgid="5043437571863443281">"PTP USB:n kautta on käytössä"</string>
@@ -1367,7 +1367,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Analoginen äänilaite havaittu"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Liitetty laite ei ole yhteensopiva puhelimen kanssa. Napauta, niin näet lisätietoja."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"USB-vianetsintä yhdistetty"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Laita USB-vianetsintä pois päältä napauttamalla"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Sulje USB-vianetsintä napauttamalla"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Poista USB-vianetsintä käytöstä valitsemalla tämä."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Langaton virheenkorjaus yhdistetty"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Poista langaton virheenkorjaus käytöstä napauttamalla"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 2660df69d04b..f04e71e3e1aa 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -209,8 +209,8 @@
<string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, contactez l\'administrateur de votre organisation."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activez votre profil pro"</string>
- <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vos applications personnelles seront bloquées jusqu\'à ce que vous activiez votre profil professionnel"</string>
- <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Vos applications personnelles seront bloquées le <xliff:g id="DATE">%1$s</xliff:g> à <xliff:g id="TIME">%2$s</xliff:g>. Votre administrateur informatique ne vous autorise pas à désactiver votre profil professionnel pendant plus de <xliff:g id="NUMBER">%3$d</xliff:g> jours."</string>
+ <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vos applis perso sont bloquées tant que vous n\'avez pas activé votre profil pro"</string>
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Vos applis perso seront bloquées le <xliff:g id="DATE">%1$s</xliff:g> à <xliff:g id="TIME">%2$s</xliff:g>. Votre administrateur ne permet pas que votre profil pro reste désactivé pendant plus de <xliff:g id="NUMBER">%3$d</xliff:g> jours."</string>
<string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activer"</string>
<string name="me" msgid="6207584824693813140">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string>
@@ -1869,7 +1869,7 @@
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"L\'économiseur de batterie active le thème sombre et limite ou désactive les activités en arrière-plan ainsi que certains effets visuels, fonctionnalités et connexions réseau."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"L\'économiseur de batterie active le thème sombre et limite ou désactive les activités en arrière-plan ainsi que certains effets visuels, fonctionnalités et connexions réseau."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pour réduire la consommation des données, l\'Économiseur de données empêche certaines applis d\'envoyer ou de recevoir des données en arrière-plan. Les applis que vous utiliserez pourront toujours accéder aux données, mais le feront moins fréquemment. Par exemple, les images pourront ne pas s\'afficher tant que vous n\'aurez pas appuyé pas dessus."</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données ?"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'Économiseur de données ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="one">Pendant %1$d minute (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -2070,7 +2070,7 @@
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
<string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"Vibreur pour les appels et les notifications"</string>
- <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Sonnerie désactivée pour les appels et les notifications"</string>
+ <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"Sons désactivés pour les appels et les notifications"</string>
<string name="notification_channel_system_changes" msgid="2462010596920209678">"Modifications du système"</string>
<string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Ne pas déranger"</string>
<string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Nouveau : Le mode Ne pas déranger masque les notifications"</string>
@@ -2157,7 +2157,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Impossible de partager ce contenu avec des applis personnelles"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Impossible d\'ouvrir ce contenu avec des applis personnelles"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Profil professionnel en pause"</string>
- <string name="resolver_switch_on_work" msgid="463709043650610420">"Appuyer pour activer"</string>
+ <string name="resolver_switch_on_work" msgid="463709043650610420">"Appuyez pour l\'activer"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Aucune appli professionnelle"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Aucune appli personnelle"</string>
<string name="miniresolver_open_in_personal" msgid="2937599899213467617">"Ouvrir dans <xliff:g id="APP">%s</xliff:g> avec le profil personnel ?"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d686450a6f3c..fd45cce3e5ec 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -990,7 +990,7 @@
<string name="autofill_province" msgid="3676846437741893159">"प्रांत"</string>
<string name="autofill_postal_code" msgid="7034789388968295591">"डाक कोड"</string>
<string name="autofill_state" msgid="3341725337190434069">"राज्य"</string>
- <string name="autofill_zip_code" msgid="1315503730274962450">"ज़िप कोड"</string>
+ <string name="autofill_zip_code" msgid="1315503730274962450">"पिन कोड"</string>
<string name="autofill_county" msgid="7781382735643492173">"काउंटी"</string>
<string name="autofill_island" msgid="5367139008536593734">"द्वीप"</string>
<string name="autofill_district" msgid="6428712062213557327">"जिला"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index c430c4ab39db..9e0fb1edc610 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2190,7 +2190,7 @@
<string name="resolver_cant_access_work_apps_explanation" msgid="1129960195389373279">"Taj se sadržaj ne može otvoriti pomoću poslovnih aplikacija"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Taj se sadržaj ne može dijeliti pomoću osobnih aplikacija"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Taj se sadržaj ne može otvoriti pomoću osobnih aplikacija"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Poslovni je profil pauziran"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Poslovni profil je pauziran"</string>
<string name="resolver_switch_on_work" msgid="463709043650610420">"Dodirnite da biste uključili"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Poslovne aplikacije nisu dostupne"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Osobne aplikacije nisu dostupne"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 1ff6e9dcb9a0..b84778fbdcd0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -2225,7 +2225,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"אי אפשר לשתף את התוכן הזה עם אפליקציות לשימוש אישי"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"אי אפשר לפתוח את התוכן הזה באמצעות אפליקציות לשימוש אישי"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"פרופיל העבודה מושהה"</string>
- <string name="resolver_switch_on_work" msgid="463709043650610420">"יש להקיש כדי להפעיל"</string>
+ <string name="resolver_switch_on_work" msgid="463709043650610420">"יש להקיש כדי להפעיל את פרופיל העבודה"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"אין אפליקציות לעבודה"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"אין אפליקציות לשימוש אישי"</string>
<string name="miniresolver_open_in_personal" msgid="2937599899213467617">"לפתוח באפליקציה <xliff:g id="APP">%s</xliff:g> בפרופיל האישי?"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 9e72ec87dac5..ff5edfebc131 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -246,7 +246,7 @@
<string name="global_action_lock" msgid="6949357274257655383">"Экранды құлыптау"</string>
<string name="global_action_power_off" msgid="4404936470711393203">"Өшіру"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"Қуат"</string>
- <string name="global_action_restart" msgid="4678451019561687074">"Қайта қосу"</string>
+ <string name="global_action_restart" msgid="4678451019561687074">"Өшіріп қосу"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"Төтенше жағдай"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"Вирус туралы хабарлау"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Сеансты аяқтау"</string>
@@ -442,7 +442,7 @@
<string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"болжалды орналасқан жер туралы ақпаратқа тек ашық экранда кіру"</string>
<string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Бұл қолданба пайдаланылып жатқанда, ол Локация қызметтерінен болжалды геодерегіңізді ала алады. Геодеректі алу үшін құрылғыңызға арналған Локация қызметтері қосулы тұруы керек."</string>
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"геодеректерді фондық режимде пайдалану"</string>
- <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Бұл қолданба пайдаланылмайтын кезде де, ол геодеректі кез келген уақытта пайдалана алады."</string>
+ <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Бұл қолданба кез келген уақытта (пайдаланылмайтын кезде де) локацияны пайдалана алады."</string>
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"аудио параметрлерін өзгерту"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Қолданбаға дыбыс қаттылығы және аудио шығыс үндеткішін таңдау сияқты жаһандық аудио параметрлерін өзгерту мүмкіндігін береді."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"аудио жазу"</string>
@@ -971,7 +971,7 @@
<string name="factorytest_failed" msgid="3190979160945298006">"Зауыт тесті орындалмады."</string>
<string name="factorytest_not_system" msgid="5658160199925519869">"ЗАУЫТ_TEСТІ әрекетінің қолдауы жүйеде/қолданбада орнатылған жинақтар үшін ғана ұсынылған."</string>
<string name="factorytest_no_action" msgid="339252838115675515">"ЗАУЫТ_TEСТІ әрекетін жабдықтайтын жинақ табылмады."</string>
- <string name="factorytest_reboot" msgid="2050147445567257365">"Қайта қосу"</string>
+ <string name="factorytest_reboot" msgid="2050147445567257365">"Өшіріп қосу"</string>
<string name="js_dialog_title" msgid="7464775045615023241">"\"<xliff:g id="TITLE">%s</xliff:g>\" парағында былай делінген:"</string>
<string name="js_dialog_title_default" msgid="3769524569903332476">"JavaScript"</string>
<string name="js_dialog_before_unload_title" msgid="7012587995876771246">"Жылжуды растау"</string>
@@ -1239,7 +1239,7 @@
<string name="unsupported_display_size_show" msgid="980129850974919375">"Үнемі көрсету"</string>
<string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы сіздің Android OЖ-бен үйлеспейді және дұрыс жұмыс істемеуі ықтимал. Қолданбаның жаңартылған нұсқасы қолжетімді болуы мүмкін."</string>
<string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Үнемі көрсету"</string>
- <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Жаңа нұсқасының бар-жоғын тексеру"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Жаңарту бар-жоғын тексеру"</string>
<string name="smv_application" msgid="3775183542777792638">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасы (<xliff:g id="PROCESS">%2$s</xliff:g> процесі) өзі қолданған StrictMode саясатын бұзды."</string>
<string name="smv_process" msgid="1398801497130695446">"<xliff:g id="PROCESS">%1$s</xliff:g> үрдісі өздігінен күшіне енген ҚатаңРежим ережесін бұзды."</string>
<string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Телефон жаңартылуда…"</string>
@@ -1830,7 +1830,7 @@
<string name="reason_unknown" msgid="5599739807581133337">"белгісіз"</string>
<string name="reason_service_unavailable" msgid="5288405248063804713">"Принтер қызметі қосылмаған"</string>
<string name="print_service_installed_title" msgid="6134880817336942482">"<xliff:g id="NAME">%s</xliff:g> қызметі орнатылды"</string>
- <string name="print_service_installed_message" msgid="7005672469916968131">"Қосу үшін түрту"</string>
+ <string name="print_service_installed_message" msgid="7005672469916968131">"Қосу үшін түртіңіз"</string>
<string name="restr_pin_enter_admin_pin" msgid="1199419462726962697">"Әкімшінің PIN кодын енгізіңіз"</string>
<string name="restr_pin_enter_pin" msgid="373139384161304555">"PIN енгізу"</string>
<string name="restr_pin_incorrect" msgid="3861383632940852496">"Дұрыс емес"</string>
@@ -1976,7 +1976,7 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Қолданба Android жүйесінің ескі нұсқасына арналған және дұрыс жұмыс істемеуі мүмкін. Жаңартылған нұсқаны тексеріңіз немесе әзірлеушіге хабарласыңыз."</string>
- <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңа нұсқасының бар-жоғын тексеру"</string>
+ <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңарту бар-жоғын тексеру"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"Сізде жаңа хабарлар бар"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Көру үшін SMS қолданбасын ашыңыз"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Кейбір функциялар істемеуі мүмкін."</string>
@@ -2157,7 +2157,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Бұл мазмұнды жеке қолданбалармен бөлісу мүмкін емес."</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Бұл мазмұнды жеке қолданбалармен ашу мүмкін емес."</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Жұмыс профилі кідіртілді."</string>
- <string name="resolver_switch_on_work" msgid="463709043650610420">"Қосу үшін түрту"</string>
+ <string name="resolver_switch_on_work" msgid="463709043650610420">"Қосу үшін түртіңіз"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Жұмыс қолданбалары жоқ."</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Жеке қолданбалар жоқ."</string>
<string name="miniresolver_open_in_personal" msgid="2937599899213467617">"Жеке профильдегі <xliff:g id="APP">%s</xliff:g> қолданбасында ашу керек пе?"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 470683d06134..a297d535dac1 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1866,8 +1866,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-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5474a493c609..44d751e60e41 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -2157,7 +2157,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"이 콘텐츠는 개인 앱을 통해 공유할 수 없습니다."</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"이 콘텐츠는 개인 앱으로 열 수 없습니다."</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"직장 프로필이 일시중지됨"</string>
- <string name="resolver_switch_on_work" msgid="463709043650610420">"탭하여 사용"</string>
+ <string name="resolver_switch_on_work" msgid="463709043650610420">"탭하여 사용 설정"</string>
<string name="resolver_no_work_apps_available" msgid="3298291360133337270">"직장 앱 없음"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"개인 앱 없음"</string>
<string name="miniresolver_open_in_personal" msgid="2937599899213467617">"개인 프로필의 <xliff:g id="APP">%s</xliff:g>에서 여시겠습니까?"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 984e6f6a2166..c8f94fbbc5bd 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1259,7 +1259,7 @@
<string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Экран өчүрүлсүнбү?"</string>
<string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Манжаңыздын изин жөндөп жатканда күйгүзүү/өчүрүү баскычын басып алдыңыз.\n\nБул адатта экранды өчүрөт."</string>
<string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Өчүрүү"</string>
- <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Жокко чыгаруу"</string>
+ <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Жок"</string>
<string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> иштеп жатат"</string>
<string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Оюнга кайтуу үчүн таптаңыз"</string>
<string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Оюн тандоо"</string>
@@ -1683,10 +1683,10 @@
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ыкчам иштетесизби?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең 3 секунддай коё бербей басып туруңуз."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Атайын мүмкүнчүлүктөрдүн ыкчам баскычын иштетесизби?"</string>
- <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн, үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Жөндөөлөр &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
+ <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Жөндөөлөр &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ыкчам баскычын иштетесизби?"</string>
- <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн, үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Жөндөөлөр &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
+ <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Жөндөөлөр &gt; Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ооба"</string>
<string name="accessibility_shortcut_off" msgid="3651336255403648739">"Жок"</string>
<string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"КҮЙҮК"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 69e3c74ea601..9d14a8d3834c 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1239,7 +1239,7 @@
<string name="unsupported_display_size_show" msgid="980129850974919375">"नेहमी दर्शवा"</string>
<string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे Android OS च्या विसंगत आवृत्तीसाठी तयार केले होते आणि ते अनपेक्षित पद्धतीने काम करू शकते. ॲपची अपडेट केलेली आवृत्ती उपलब्ध असू शकते."</string>
<string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"नेहमी दर्शवा"</string>
- <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"अपडेट आहे का ते तपासा"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"अपडेटसाठी तपासा"</string>
<string name="smv_application" msgid="3775183542777792638">"अ‍ॅप <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने तिच्या स्वयं-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले आहे."</string>
<string name="smv_process" msgid="1398801497130695446">"<xliff:g id="PROCESS">%1$s</xliff:g> प्रक्रियेने तिच्या स्वतः-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले."</string>
<string name="android_upgrading_title" product="default" msgid="7279077384220829683">"फोन अपडेट होत आहे…"</string>
@@ -1976,7 +1976,7 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"हे अ‍ॅप Android च्या जुन्या आवृत्ती साठी तयार करण्यात आले होते आणि योग्यरितीने कार्य करू शकणार नाही. अपडेट आहेत का ते तपासून पाहा, किंवा डेव्हलपरशी संपर्क साधण्याचा प्रयत्न करा."</string>
- <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अपडेट आहे का ते तपासा"</string>
+ <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अपडेटसाठी तपासा"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"आपल्याकडे नवीन मेसेज आहेत"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"पाहण्‍यासाठी SMS अ‍ॅप उघडा"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"काही कार्यक्षमता मर्यादित असू शकतात"</string>
@@ -2117,8 +2117,8 @@
<string name="mime_type_document_ext" msgid="2398002765046677311">"<xliff:g id="EXTENSION">%1$s</xliff:g> दस्तऐवज"</string>
<string name="mime_type_spreadsheet" msgid="8188407519131275838">"स्प्रेडशीट"</string>
<string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> स्प्रेडशीट"</string>
- <string name="mime_type_presentation" msgid="1145384236788242075">"सादरीकरण"</string>
- <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> सादरीकरण"</string>
+ <string name="mime_type_presentation" msgid="1145384236788242075">"प्रेझेंटेशन"</string>
+ <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> प्रेझेंटेशन"</string>
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"विमान मोड दरम्यान ब्लूटूथ सुरू राहील"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"लोड होत आहे"</string>
<plurals name="file_count" formatted="false" msgid="7063513834724389247">
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 13a17366f0e4..d565c28faaf8 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -198,7 +198,7 @@
<string name="location_changed_notification_text" msgid="7158423339982706912">"थप जानकारी प्राप्त गर्न आफ्ना IT प्रशासकसँग सम्पर्क गर्नुहोस्"</string>
<string name="geofencing_service" msgid="3826902410740315456">"जियोफेन्सिङ सेवा"</string>
<string name="country_detector" msgid="7023275114706088854">"देश पत्ता लगाउने सुविधा"</string>
- <string name="location_service" msgid="2439187616018455546">"स्थानसम्बन्धी सेवा"</string>
+ <string name="location_service" msgid="2439187616018455546">"लोकेसन सर्भिस"</string>
<string name="gnss_service" msgid="8907781262179951385">"GNSS सेवा"</string>
<string name="sensor_notification_service" msgid="7474531979178682676">"सेन्सरको सूचनासम्बन्धी सेवा"</string>
<string name="twilight_service" msgid="8964898045693187224">"ट्वाइलाइट सेवा"</string>
@@ -910,7 +910,7 @@
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"तपाईंले गलत तरिकाले आफ्नो पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक टाइप गर्नुभयो। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"तपाईँले गलत तरिकाले तपाईँको PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक टाइप गर्नु भएको छ। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"तपाईँले तपाईँको अनलक प्याटर्न गलत तरिकाले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक खिच्नु भएको छ। पछि <xliff:g id="NUMBER_1">%2$d</xliff:g> थप असफल कोसिसहरू, तपाईँको Google साइन इन प्रयोग गरी तपाईँको ट्याब्लेट अनलक गर्न भनिने छ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फरि प्रयास गर्नुहोस्।"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"तपाईंले आफ्नो अनलक शैली <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले कोर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंलाई आफ्नो Google खाता मार्फत साइन इन गरेर आफ्नो Android टिभी यन्त्र अनलक गर्न अनुरोध गरिनेछ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डपछि फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"तपाईंले आफ्नो अनलक शैली <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले कोर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंलाई आफ्नो Google खाता मार्फत साइन इन गरेर आफ्नो Android टिभी डिभाइस अनलक गर्न अनुरोध गरिनेछ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डपछि फेरि प्रयास गर्नुहोस्।"</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"तपाईँले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले तपाईँको अनलक ढाँचालाई कोर्नु भएको छ। पछि <xliff:g id="NUMBER_1">%2$d</xliff:g> अरू धेरै असफल कोसिसहरूपछि, तपाईँलाई तपाईँको फोन Google साइन इन प्रयोग गरेर अनलक गर्नको लागि सोधिने छ। \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा पुनः प्रयास गर्नुहोस्।"</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"तपाईँले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक ट्याब्लेटलाई अनलक गर्नको लागि गलत तरिकाले कोशिस गर्नुभएको छ। <xliff:g id="NUMBER_1">%2$d</xliff:g> अरू धेरै असफल कोसिसहरूपछि, ट्याब्लेट फ्याट्रि पूर्वनिर्धारितमा रिसेट हुने छ र सबै प्रयोगकर्ता डेटा हराउने छन्।"</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"तपाईंले आफ्नो Android टिभी यन्त्र <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंको Android टिभी यन्त्रलाई रिसेट गरेर डिफल्ट फ्याक्ट्री सेटिङ लागू गरिने छ र प्रयोगकर्ताको सम्पूर्ण डेटा गुम्ने छ।"</string>
@@ -1393,7 +1393,7 @@
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string>
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"अरू एपमाथि देखाउनुहोस्"</string>
+ <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"अरू एपमाथि देखाइयोस्"</string>
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> अन्य एपहरूमा देखिँदैछ"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> अन्य एपहरूमा देखिँदैछ"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"तपाईं <xliff:g id="NAME">%s</xliff:g> ले यो विशेषता प्रयोग नगरेको चाहनुहुन्न भने सेटिङहरू खोली यसलाई निष्क्रिय पार्न ट्याप गर्नुहोस्।"</string>
@@ -1675,7 +1675,7 @@
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"तपाईंले आफ्नो Android टिभी यन्त्र <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले अनलक गर्ने प्रयास गर्नुभएको छ। अब तपाईंको Android टिभी यन्त्रलाई रिसेट गरेर डिफल्ट फ्याक्ट्री सेटिङ लागू गरिनेछ।"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"तपाईंले गलत तरिकाले फोन <xliff:g id="NUMBER">%d</xliff:g> पटक अनलक गर्ने प्रयत्न गर्नुभयो। अब फोन फ्याक्ट्रि पूर्वनिर्धारितमा रिसेट हुने छ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"तपाईंले गलत तरिकाले आफ्नो अनलक प्याटर्न <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="tv" msgid="4670840383567106114">"तपाईंले आफ्नो अनलक शैली <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले कोर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंलाई आफ्नो इमेल खाता प्रयोग गरेर आफ्नो Android टिभी यन्त्र अनलक गर्न अनुरोध गरिनेछ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डपछि फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"तपाईंले आफ्नो अनलक शैली <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले कोर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> प्रयासहरू असफल भएपछि तपाईंलाई आफ्नो इमेल खाता प्रयोग गरेर आफ्नो Android टिभी डिभाइस अनलक गर्न अनुरोध गरिनेछ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डपछि फेरि प्रयास गर्नुहोस्।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"तपाईँले आफ्नो अनलक प्याटर्न गलत रूपमा <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_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"हटाउनुहोस्"</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>
@@ -1977,7 +1976,7 @@
<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>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"यो एप Android को पुरानो संस्करणका लागि बनाइएको हुनाले यसले सही ढङ्गले काम नगर्न सक्छ। अद्यावधिकहरू उपलब्ध छन् वा छैनन् भनी जाँच गरी हेर्नुहोस् वा यसको विकासकर्तालाई सम्पर्क गर्नुहोस्।"</string>
- <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अद्यावधिक उपलब्ध छ वा छैन भनी जाँच गर्नुहोस्"</string>
+ <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अपडेट उपलब्ध छ वा छैन जाँच्नुहोस्"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"तपाईंलाई नयाँ सन्देश आएको छ"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"हेर्नका लागि SMS एप खोल्नुहोस्"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"केही सुविधा राम्ररी नचल्न सक्छन्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 4dc2a1b6d3b2..531612423a83 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1868,7 +1868,7 @@
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
<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_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 getoond totdat je erop tikt."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Databesparing aanzetten?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aanzetten"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index d12bb0b06b43..d2165cbab44a 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -223,7 +223,7 @@
<string name="power_off" msgid="4111692782492232778">"ପାୱାର୍ ବନ୍ଦ"</string>
<string name="silent_mode_silent" msgid="5079789070221150912">"ରିଙ୍ଗର୍‍ ଅଫ୍‍ ଅଛି"</string>
<string name="silent_mode_vibrate" msgid="8821830448369552678">"ରିଙ୍ଗର୍‍ କମ୍ପନ"</string>
- <string name="silent_mode_ring" msgid="6039011004781526678">"ରିଙ୍ଗର୍‍ ଅନ୍‍ ଅଛି"</string>
+ <string name="silent_mode_ring" msgid="6039011004781526678">"ରିଙ୍ଗର୍‍ ଚାଲୁ ଅଛି"</string>
<string name="reboot_to_update_title" msgid="2125818841916373708">"Android ସିଷ୍ଟମ୍‍ ଅପଡେଟ୍‍"</string>
<string name="reboot_to_update_prepare" msgid="6978842143587422365">"ଅପଡେଟ୍‍ କରିବାକୁ ପ୍ରସ୍ତୁତ କରାଯାଉଛି…"</string>
<string name="reboot_to_update_package" msgid="4644104795527534811">"ଅପଡେଟ୍‍ ପ୍ୟାକେଜ୍‍ ପ୍ରୋସେସ୍‍ କରାଯାଉଛି…"</string>
@@ -265,7 +265,7 @@
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ବଗ୍ ରିପୋର୍ଟ ସହ ସ୍କ୍ରିନସଟ୍ ନେବାରେ ବିଫଳ ହୋଇଛି"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ସାଇଲେଣ୍ଟ ମୋଡ୍"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ସାଉଣ୍ଡ ଅଫ୍ ଅଛି"</string>
- <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ସାଉଣ୍ଡ ଅନ୍ ଅଛି"</string>
+ <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ସାଉଣ୍ଡ ଚାଲୁ ଅଛି"</string>
<string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"ଏରୋପ୍ଲେନ୍‍ ମୋଡ୍"</string>
<string name="global_actions_airplane_mode_on_status" msgid="5508025516695361936">"ଏରୋପ୍ଲେନ୍‍ ମୋଡ୍ ଅନ୍ ଅଛି"</string>
<string name="global_actions_airplane_mode_off_status" msgid="8522219771500505475">"ଏରୋପ୍ଲେନ୍‍ ମୋଡ୍ ଅଫ୍ ଅଛି"</string>
@@ -930,7 +930,7 @@
<string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"ଆପଣଙ୍କର ଯୁଜରନେମ୍‌ କିମ୍ୱା ପାସୱାର୍ଡ ଭୁଲି ଯାଇଛନ୍ତି କି?\n"<b>"google.com/accounts/recovery"</b>" ଭିଜିଟ୍‍ କରନ୍ତୁ।"</string>
<string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"ଯାଞ୍ଚ କରାଯାଉଛି…"</string>
<string name="lockscreen_unlock_label" msgid="4648257878373307582">"ଅନଲକ୍‌"</string>
- <string name="lockscreen_sound_on_label" msgid="1660281470535492430">"ସାଉଣ୍ଡ ଅନ୍ ଅଛି"</string>
+ <string name="lockscreen_sound_on_label" msgid="1660281470535492430">"ସାଉଣ୍ଡ ଚାଲୁ ଅଛି"</string>
<string name="lockscreen_sound_off_label" msgid="2331496559245450053">"ସାଉଣ୍ଡ ଅଫ୍ ଅଛି"</string>
<string name="lockscreen_access_pattern_start" msgid="3778502525702613399">"ପାଟର୍ନ ଆରମ୍ଭ ହେଲା"</string>
<string name="lockscreen_access_pattern_cleared" msgid="7493849102641167049">"ପାଟର୍ନ ଖାଲି କରାଗଲା"</string>
@@ -1033,7 +1033,7 @@
<string name="menu_function_shortcut_label" msgid="2367112760987662566">"Function+"</string>
<string name="menu_space_shortcut_label" msgid="5949311515646872071">"ସ୍ପେସ୍‍"</string>
<string name="menu_enter_shortcut_label" msgid="6709499510082897320">"ଏଣ୍ଟର୍"</string>
- <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"ଡିଲିଟ୍‍"</string>
+ <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"ଡିଲିଟ୍‌ କରନ୍ତୁ"</string>
<string name="search_go" msgid="2141477624421347086">"Search"</string>
<string name="search_hint" msgid="455364685740251925">"ସର୍ଚ୍ଚ…"</string>
<string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 1436d47666eb..91dd2fc5219a 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1866,10 +1866,9 @@
<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_description" msgid="4995164271550590517">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਕਰਨ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ਚਾਲੂ ਕਰੋ"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 89eb90c8788b..c3c5d0a93623 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1724,7 +1724,7 @@
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Usuń"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zwiększyć głośność ponad zalecany poziom?\n\nSłuchanie głośno przez długi czas może uszkodzić Twój słuch."</string>
- <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Użyć skrótu do ułatwień dostępu?"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Użyć skrótu ułatwień dostępu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Gdy skrót jest włączony, jednoczesne naciskanie przez trzy sekundy obu przycisków głośności uruchamia funkcję ułatwień dostępu."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Włączyć skrót ułatwień dostępu?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Przytrzymanie obu klawiszy głośności przez kilka sekund włącza ułatwienia dostępu. Może to zmienić sposób działania urządzenia.\n\nBieżące funkcje:\n<xliff:g id="SERVICE">%1$s</xliff:g>\naby zmienić wybrane funkcje, kliknij Ustawienia &gt; Ułatwienia dostępu."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index dd899de8a74b..42e3b5bb1cbb 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1367,7 +1367,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Acessório de áudio analógico detectado"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"O dispositivo anexo não é compatível com esse smartphone. Toque para saber mais."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Depuração USB conectada"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB."</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecione para desativar a depuração USB."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração por Wi-Fi conectada"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração por Wi-Fi"</string>
@@ -1869,7 +1869,7 @@
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar a Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="one">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index dd899de8a74b..42e3b5bb1cbb 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1367,7 +1367,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Acessório de áudio analógico detectado"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"O dispositivo anexo não é compatível com esse smartphone. Toque para saber mais."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Depuração USB conectada"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB."</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecione para desativar a depuração USB."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração por Wi-Fi conectada"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração por Wi-Fi"</string>
@@ -1869,7 +1869,7 @@
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
<string name="battery_saver_description" msgid="8518809702138617167">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
- <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
+ <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar a Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
<item quantity="one">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 658ab8d7b57c..ebdde2378db2 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1406,8 +1406,8 @@
<string name="usb_power_notification_message" msgid="7284765627437897702">"Polnjenje akumulatorja v povezani napravi. Dotaknite se za več možnosti."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Zaznana je analogna dodatna zvočna oprema"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Priključena naprava ni združljiva s tem telefonom. Dotaknite se za več informacij."</string>
- <string name="adb_active_notification_title" msgid="408390247354560331">"Iskanje napak prek USB je povezano"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Dotaknite se, če želite izklop. odpravlj. napak prek USB-ja"</string>
+ <string name="adb_active_notification_title" msgid="408390247354560331">"Iskanje napak prek USB-ja je povezano"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Dotaknite se, če želite izklopiti odpravljanje napak prek USB-ja."</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Izberite, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Povezava za brezžično odpravljanje napak je vzpostavljena"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Dotaknite se, če želite izklopiti brezžično odpravljanje napak."</string>
@@ -2226,7 +2226,7 @@
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Te vsebine ni mogoče odpreti z osebnimi aplikacijami."</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Delovni profil je začasno zaustavljen"</string>
<string name="resolver_switch_on_work" msgid="463709043650610420">"Dotaknite se za vklop"</string>
- <string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nobena delovna aplikacija"</string>
+ <string name="resolver_no_work_apps_available" msgid="3298291360133337270">"Nobena delovna aplikacija ni na voljo"</string>
<string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Nobena osebna aplikacija"</string>
<string name="miniresolver_open_in_personal" msgid="2937599899213467617">"Želite odpreti v aplikaciji <xliff:g id="APP">%s</xliff:g> v osebnem profilu?"</string>
<string name="miniresolver_open_in_work" msgid="152208044699347924">"Želite odpreti v aplikaciji <xliff:g id="APP">%s</xliff:g> v delovnem profilu?"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 7a363f10f76c..f9fbe65230f2 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -247,7 +247,7 @@
<string name="global_action_power_off" msgid="4404936470711393203">"పవర్ ఆఫ్ చేయి"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"పవర్"</string>
<string name="global_action_restart" msgid="4678451019561687074">"రీస్టార్ట్ చేయి"</string>
- <string name="global_action_emergency" msgid="1387617624177105088">"అత్యవసరం"</string>
+ <string name="global_action_emergency" msgid="1387617624177105088">"ఎమర్జెన్సీ"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"బగ్ నివేదిక"</string>
<string name="global_action_logout" msgid="6093581310002476511">"సెషన్‌ను ముగించు"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"స్క్రీన్‌షాట్"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 9fee7d85f252..0bbaa7898bc2 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1355,7 +1355,7 @@
<string name="no_permissions" msgid="5729199278862516390">"Hech qanday ruxsat talab qilinmaydi"</string>
<string name="perm_costs_money" msgid="749054595022779685">"buning uchun sizdan haq olinishi mumkin"</string>
<string name="dlg_ok" msgid="5103447663504839312">"OK"</string>
- <string name="usb_charging_notification_title" msgid="1674124518282666955">"Bu qurilma USB orqali quvvatlanmoqda"</string>
+ <string name="usb_charging_notification_title" msgid="1674124518282666955">"Qurilma USB orqali quvvatlanmoqda"</string>
<string name="usb_supplying_notification_title" msgid="5378546632408101811">"USB orqali ulangan qurilma quvvatlanmoqda"</string>
<string name="usb_mtp_notification_title" msgid="1065989144124499810">"USB orqali fayl uzatish yoqildi"</string>
<string name="usb_ptp_notification_title" msgid="5043437571863443281">"USB orqali PTP rejimi yoqildi"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1198cf634764..1fca2e90dfae 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 240d0565bddb..04291e3dcc5c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -488,6 +488,7 @@ applications that come with the platform
<permission name="android.permission.BRIGHTNESS_SLIDER_USAGE" />
<permission name="android.permission.ACCESS_AMBIENT_LIGHT_STATS" />
<permission name="android.permission.CONFIGURE_DISPLAY_BRIGHTNESS" />
+ <permission name="android.permission.GET_TOP_ACTIVITY_INFO" />
<permission name="android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER" />
<permission name="android.permission.SET_MEDIA_KEY_LISTENER" />
<permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
diff --git a/keystore/java/android/security/GenerateRkpKey.java b/keystore/java/android/security/GenerateRkpKey.java
index cc1ec1bada50..a1a7aa85519f 100644
--- a/keystore/java/android/security/GenerateRkpKey.java
+++ b/keystore/java/android/security/GenerateRkpKey.java
@@ -22,10 +22,6 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
/**
* GenerateKey is a helper class to handle interactions between Keystore and the RemoteProvisioner
@@ -45,25 +41,14 @@ import java.util.concurrent.TimeUnit;
* @hide
*/
public class GenerateRkpKey {
- private static final String TAG = "GenerateRkpKey";
-
- private static final int NOTIFY_EMPTY = 0;
- private static final int NOTIFY_KEY_GENERATED = 1;
- private static final int TIMEOUT_MS = 1000;
private IGenerateRkpKeyService mBinder;
private Context mContext;
- private CountDownLatch mCountDownLatch;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
mBinder = IGenerateRkpKeyService.Stub.asInterface(service);
- mCountDownLatch.countDown();
- }
-
- @Override public void onBindingDied(ComponentName className) {
- mCountDownLatch.countDown();
}
@Override
@@ -79,51 +64,36 @@ public class GenerateRkpKey {
mContext = context;
}
- private void bindAndSendCommand(int command, int securityLevel) throws RemoteException {
+ /**
+ * Fulfills the use case of (2) described in the class documentation. Blocks until the
+ * RemoteProvisioner application can get new attestation keys signed by the server.
+ */
+ public void notifyEmpty(int securityLevel) throws RemoteException {
Intent intent = new Intent(IGenerateRkpKeyService.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
- if (comp == null) {
- throw new RemoteException("Could not resolve GenerateRkpKeyService.");
- }
intent.setComponent(comp);
- mCountDownLatch = new CountDownLatch(1);
- if (!mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
- throw new RemoteException("Failed to bind to GenerateRkpKeyService");
- }
- try {
- mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted: ", e);
+ if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ throw new RemoteException("Failed to bind to GenerateKeyService");
}
if (mBinder != null) {
- switch (command) {
- case NOTIFY_EMPTY:
- mBinder.generateKey(securityLevel);
- break;
- case NOTIFY_KEY_GENERATED:
- mBinder.notifyKeyGenerated(securityLevel);
- break;
- default:
- Log.e(TAG, "Invalid case for command");
- }
- } else {
- Log.e(TAG, "Binder object is null; failed to bind to GenerateRkpKeyService.");
+ mBinder.generateKey(securityLevel);
}
mContext.unbindService(mConnection);
}
/**
- * Fulfills the use case of (2) described in the class documentation. Blocks until the
- * RemoteProvisioner application can get new attestation keys signed by the server.
- */
- public void notifyEmpty(int securityLevel) throws RemoteException {
- bindAndSendCommand(NOTIFY_EMPTY, securityLevel);
- }
-
- /**
- * Fulfills the use case of (1) described in the class documentation. Non blocking call.
+ * FUlfills the use case of (1) described in the class documentation. Non blocking call.
*/
public void notifyKeyGenerated(int securityLevel) throws RemoteException {
- bindAndSendCommand(NOTIFY_KEY_GENERATED, securityLevel);
+ Intent intent = new Intent(IGenerateRkpKeyService.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ throw new RemoteException("Failed to bind to GenerateKeyService");
+ }
+ if (mBinder != null) {
+ mBinder.notifyKeyGenerated(securityLevel);
+ }
+ mContext.unbindService(mConnection);
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index c048f3bffc75..dc7f3dda35c0 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -580,7 +580,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
} catch (RemoteException e) {
// This is not really an error state, and necessarily does not apply to non RKP
// systems or hybrid systems where RKP is not currently turned on.
- Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend.", e);
+ Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend.");
}
success = true;
return new KeyPair(publicKey, publicKey.getPrivateKey());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index b674c68b2490..f81f086e598f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -290,27 +290,6 @@ public class BubbleExpandedView extends LinearLayout {
applyThemeAttrs();
setClipToPadding(false);
- setOnTouchListener((view, motionEvent) -> {
- if (mTaskView == null) {
- return false;
- }
-
- final Rect avBounds = new Rect();
- mTaskView.getBoundsOnScreen(avBounds);
-
- // Consume and ignore events on the expanded view padding that are within the
- // ActivityView's vertical bounds. These events are part of a back gesture, and so they
- // should not collapse the stack (which all other touches on areas around the AV would
- // do).
- if (motionEvent.getRawY() >= avBounds.top
- && motionEvent.getRawY() <= avBounds.bottom
- && (motionEvent.getRawX() < avBounds.left
- || motionEvent.getRawX() > avBounds.right)) {
- return true;
- }
-
- return false;
- });
// BubbleStackView is forced LTR, but we want to respect the locale for expanded view layout
// so the Manage button appears on the right.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 8613dcbda872..16b8150467fd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -852,13 +852,6 @@ public class BubbleStackView extends FrameLayout
mTaskbarScrim.setAlpha(0f);
mTaskbarScrim.setVisibility(GONE);
- setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
- if (!mIsExpanded || mIsExpansionAnimating) {
- return view.onApplyWindowInsets(insets);
- }
- return view.onApplyWindowInsets(insets);
- });
-
mOrientationChangedListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
mPositioner.update();
@@ -908,20 +901,16 @@ public class BubbleStackView extends FrameLayout
}
});
- // If the stack itself is touched, it means none of its touchable views (bubbles, flyouts,
- // ActivityViews, etc.) were touched. Collapse the stack if it's expanded.
- setOnTouchListener((view, ev) -> {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (mShowingManage) {
- showManageMenu(false /* show */);
- } else if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
- mStackEduView.hide(false);
- } else if (mBubbleData.isExpanded()) {
- mBubbleData.setExpanded(false);
- }
+ // If the stack itself is clicked, it means none of its touchable views (bubbles, flyouts,
+ // TaskView, etc.) were touched. Collapse the stack if it's expanded.
+ setOnClickListener(view -> {
+ if (mShowingManage) {
+ showManageMenu(false /* show */);
+ } else if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
+ mStackEduView.hide(false);
+ } else if (mBubbleData.isExpanded()) {
+ mBubbleData.setExpanded(false);
}
-
- return true;
});
animate()
@@ -2465,6 +2454,10 @@ public class BubbleStackView extends FrameLayout
}
} else {
mBubbleContainer.getBoundsOnScreen(outRect);
+ // Account for the IME in the touchable region so that the touchable region of the
+ // Bubble window doesn't obscure the IME. The touchable region affects which areas
+ // of the screen can be excluded by lower windows (IME is just above the embedded task)
+ outRect.bottom -= (int) mStackAnimationController.getImeHeight();
}
if (mFlyout.getVisibility() == View.VISIBLE) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 12d55b85fac6..0802fb59a008 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -529,6 +529,11 @@ public class StackAnimationController extends
mImeHeight = imeHeight;
}
+ /** Returns the current IME height that the stack is offset by. */
+ public float getImeHeight() {
+ return mImeHeight;
+ }
+
/**
* Animates the stack either away from the newly visible IME, or back to its original position
* due to the IME going away.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 9dabec7a13d0..ef113dc5e10a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -317,11 +317,11 @@ public class SystemWindows {
public void locationInParentDisplayChanged(Point offset) {}
@Override
- public void insetsChanged(InsetsState insetsState) {}
+ public void insetsChanged(InsetsState insetsState, boolean willMove, boolean willResize) {}
@Override
public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {}
+ InsetsSourceControl[] activeControls, boolean willMove, boolean willResize) {}
@Override
public void showInsets(int types, boolean fromIme) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 9fa3f69b5f60..728794de0865 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -149,10 +149,10 @@ public class PipSurfaceTransactionHelper {
// Shrink bounds (expand insets) in destination orientation.
if (clockwise) {
positionX -= insets.top * scale;
- positionY -= insets.left * scale;
+ positionY += insets.left * scale;
} else {
positionX += insets.top * scale;
- positionY += insets.left * scale;
+ positionY -= insets.left * scale;
}
}
mTmpTransform.setScale(scale, scale);
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 3a0153fa3dd8..0cde3d1242c8 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -1345,7 +1345,10 @@ uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const
}
std::unique_ptr<Theme> AssetManager2::NewTheme() {
- return std::unique_ptr<Theme>(new Theme(this));
+ constexpr size_t kInitialReserveSize = 32;
+ auto theme = std::unique_ptr<Theme>(new Theme(this));
+ theme->entries_.reserve(kInitialReserveSize);
+ return theme;
}
Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
@@ -1353,28 +1356,20 @@ Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
Theme::~Theme() = default;
-namespace {
-
-struct ThemeEntry {
+struct Theme::Entry {
+ uint32_t attr_res_id;
ApkAssetsCookie cookie;
uint32_t type_spec_flags;
Res_value value;
};
-struct ThemeType {
- int entry_count;
- ThemeEntry entries[0];
-};
-
-constexpr size_t kTypeCount = std::numeric_limits<uint8_t>::max() + 1;
-
-} // namespace
-
-struct Theme::Package {
- // Each element of Type will be a dynamically sized object
- // allocated to have the entries stored contiguously with the Type.
- std::array<util::unique_cptr<ThemeType>, kTypeCount> types;
+namespace {
+struct ThemeEntryKeyComparer {
+ bool operator() (const Theme::Entry& entry, uint32_t attr_res_id) const noexcept {
+ return entry.attr_res_id < attr_res_id;
+ }
};
+} // namespace
base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, bool force) {
ATRACE_NAME("Theme::ApplyStyle");
@@ -1387,116 +1382,74 @@ base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid,
// Merge the flags from this style.
type_spec_flags_ |= (*bag)->type_spec_flags;
- int last_type_idx = -1;
- int last_package_idx = -1;
- Package* last_package = nullptr;
- ThemeType* last_type = nullptr;
-
- // Iterate backwards, because each bag is sorted in ascending key ID order, meaning we will only
- // need to perform one resize per type.
- using reverse_bag_iterator = std::reverse_iterator<const ResolvedBag::Entry*>;
- const auto rbegin = reverse_bag_iterator(begin(*bag));
- for (auto it = reverse_bag_iterator(end(*bag)); it != rbegin; ++it) {
- const uint32_t attr_resid = it->key;
+ for (auto it = begin(*bag); it != end(*bag); ++it) {
+ const uint32_t attr_res_id = it->key;
// If the resource ID passed in is not a style, the key can be some other identifier that is not
// a resource ID. We should fail fast instead of operating with strange resource IDs.
- if (!is_valid_resid(attr_resid)) {
+ if (!is_valid_resid(attr_res_id)) {
return base::unexpected(std::nullopt);
}
- // We don't use the 0-based index for the type so that we can avoid doing ID validation
- // upon lookup. Instead, we keep space for the type ID 0 in our data structures. Since
- // the construction of this type is guarded with a resource ID check, it will never be
- // populated, and querying type ID 0 will always fail.
- const int package_idx = get_package_id(attr_resid);
- const int type_idx = get_type_id(attr_resid);
- const int entry_idx = get_entry_id(attr_resid);
-
- if (last_package_idx != package_idx) {
- std::unique_ptr<Package>& package = packages_[package_idx];
- if (package == nullptr) {
- package.reset(new Package());
- }
- last_package_idx = package_idx;
- last_package = package.get();
- last_type_idx = -1;
+ // DATA_NULL_EMPTY (@empty) is a valid resource value and DATA_NULL_UNDEFINED represents
+ // an absence of a valid value.
+ bool is_undefined = it->value.dataType == Res_value::TYPE_NULL &&
+ it->value.data != Res_value::DATA_NULL_EMPTY;
+ if (!force && is_undefined) {
+ continue;
}
- if (last_type_idx != type_idx) {
- util::unique_cptr<ThemeType>& type = last_package->types[type_idx];
- if (type == nullptr) {
- // Allocate enough memory to contain this entry_idx. Since we're iterating in reverse over
- // a sorted list of attributes, this shouldn't be resized again during this method call.
- type.reset(reinterpret_cast<ThemeType*>(
- calloc(sizeof(ThemeType) + (entry_idx + 1) * sizeof(ThemeEntry), 1)));
- type->entry_count = entry_idx + 1;
- } else if (entry_idx >= type->entry_count) {
- // Reallocate the memory to contain this entry_idx. Since we're iterating in reverse over
- // a sorted list of attributes, this shouldn't be resized again during this method call.
- const int new_count = entry_idx + 1;
- type.reset(reinterpret_cast<ThemeType*>(
- realloc(type.release(), sizeof(ThemeType) + (new_count * sizeof(ThemeEntry)))));
-
- // Clear out the newly allocated space (which isn't zeroed).
- memset(type->entries + type->entry_count, 0,
- (new_count - type->entry_count) * sizeof(ThemeEntry));
- type->entry_count = new_count;
+ Theme::Entry new_entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value};
+ auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), attr_res_id,
+ ThemeEntryKeyComparer{});
+ if (entry_it != entries_.end() && entry_it->attr_res_id == attr_res_id) {
+ if (is_undefined) {
+ // DATA_NULL_UNDEFINED clears the value of the attribute in the theme only when `force` is
+ /// true.
+ entries_.erase(entry_it);
+ } else if (force) {
+ *entry_it = new_entry;
}
- last_type_idx = type_idx;
- last_type = type.get();
- }
-
- ThemeEntry& entry = last_type->entries[entry_idx];
- if (force || (entry.value.dataType == Res_value::TYPE_NULL &&
- entry.value.data != Res_value::DATA_NULL_EMPTY)) {
- entry.cookie = it->cookie;
- entry.type_spec_flags |= (*bag)->type_spec_flags;
- entry.value = it->value;
+ } else {
+ entries_.insert(entry_it, new_entry);
}
}
return {};
}
+void Theme::Rebase(AssetManager2* am, const uint32_t* style_ids, const uint8_t* force,
+ size_t style_count) {
+ ATRACE_NAME("Theme::Rebase");
+ // Reset the entries without changing the vector capacity to prevent reallocations during
+ // ApplyStyle.
+ entries_.clear();
+ asset_manager_ = am;
+ for (size_t i = 0; i < style_count; i++) {
+ ApplyStyle(style_ids[i], force[i]);
+ }
+}
+
std::optional<AssetManager2::SelectedValue> Theme::GetAttribute(uint32_t resid) const {
- int cnt = 20;
+ constexpr const uint32_t kMaxIterations = 20;
uint32_t type_spec_flags = 0u;
- do {
- const int package_idx = get_package_id(resid);
- const Package* package = packages_[package_idx].get();
- if (package != nullptr) {
- // The themes are constructed with a 1-based type ID, so no need to decrement here.
- const int type_idx = get_type_id(resid);
- const ThemeType* type = package->types[type_idx].get();
- if (type != nullptr) {
- const int entry_idx = get_entry_id(resid);
- if (entry_idx < type->entry_count) {
- const ThemeEntry& entry = type->entries[entry_idx];
- type_spec_flags |= entry.type_spec_flags;
-
- if (entry.value.dataType == Res_value::TYPE_ATTRIBUTE) {
- if (cnt > 0) {
- cnt--;
- resid = entry.value.data;
- continue;
- }
- return std::nullopt;
- }
-
- // @null is different than @empty.
- if (entry.value.dataType == Res_value::TYPE_NULL &&
- entry.value.data != Res_value::DATA_NULL_EMPTY) {
- return std::nullopt;
- }
+ for (uint32_t i = 0; i <= kMaxIterations; i++) {
+ auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), resid,
+ ThemeEntryKeyComparer{});
+ if (entry_it == entries_.end() || entry_it->attr_res_id != resid) {
+ return std::nullopt;
+ }
- return AssetManager2::SelectedValue(entry.value.dataType, entry.value.data, entry.cookie,
- type_spec_flags, 0U /* resid */, {} /* config */);
- }
- }
+ type_spec_flags |= entry_it->type_spec_flags;
+ if (entry_it->value.dataType == Res_value::TYPE_ATTRIBUTE) {
+ resid = entry_it->value.data;
+ continue;
}
- break;
- } while (true);
+
+ return AssetManager2::SelectedValue(entry_it->value.dataType, entry_it->value.data,
+ entry_it->cookie, type_spec_flags, 0U /* resid */,
+ {} /* config */);
+ }
return std::nullopt;
}
@@ -1520,56 +1473,25 @@ base::expected<std::monostate, NullOrIOError> Theme::ResolveAttributeReference(
}
void Theme::Clear() {
- type_spec_flags_ = 0u;
- for (std::unique_ptr<Package>& package : packages_) {
- package.reset();
- }
+ entries_.clear();
}
-base::expected<std::monostate, IOError> Theme::SetTo(const Theme& o) {
- if (this == &o) {
+base::expected<std::monostate, IOError> Theme::SetTo(const Theme& source) {
+ if (this == &source) {
return {};
}
- type_spec_flags_ = o.type_spec_flags_;
-
- if (asset_manager_ == o.asset_manager_) {
- // The theme comes from the same asset manager so all theme data can be copied exactly
- for (size_t p = 0; p < packages_.size(); p++) {
- const Package *package = o.packages_[p].get();
- if (package == nullptr) {
- // The other theme doesn't have this package, clear ours.
- packages_[p].reset();
- continue;
- }
-
- if (packages_[p] == nullptr) {
- // The other theme has this package, but we don't. Make one.
- packages_[p].reset(new Package());
- }
-
- for (size_t t = 0; t < package->types.size(); t++) {
- const ThemeType *type = package->types[t].get();
- if (type == nullptr) {
- // The other theme doesn't have this type, clear ours.
- packages_[p]->types[t].reset();
- continue;
- }
+ type_spec_flags_ = source.type_spec_flags_;
- // Create a new type and update it to theirs.
- const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry));
- void *copied_data = malloc(type_alloc_size);
- memcpy(copied_data, type, type_alloc_size);
- packages_[p]->types[t].reset(reinterpret_cast<ThemeType *>(copied_data));
- }
- }
+ if (asset_manager_ == source.asset_manager_) {
+ entries_ = source.entries_;
} else {
std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
// Determine which ApkAssets are loaded in both theme AssetManagers.
- const auto src_assets = o.asset_manager_->GetApkAssets();
+ const auto src_assets = source.asset_manager_->GetApkAssets();
for (size_t i = 0; i < src_assets.size(); i++) {
const ApkAssets* src_asset = src_assets[i];
@@ -1587,7 +1509,8 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& o) {
// asset in th destination AssetManager.
SourceToDestinationRuntimePackageMap package_map;
for (const auto& loaded_package : src_asset->GetLoadedArsc()->GetPackages()) {
- const int src_package_id = o.asset_manager_->GetAssignedPackageId(loaded_package.get());
+ const int src_package_id = source.asset_manager_->GetAssignedPackageId(
+ loaded_package.get());
const int dest_package_id = asset_manager_->GetAssignedPackageId(loaded_package.get());
package_map[src_package_id] = dest_package_id;
}
@@ -1599,130 +1522,88 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& o) {
}
// Reset the data in the destination theme.
- for (size_t p = 0; p < packages_.size(); p++) {
- if (packages_[p] != nullptr) {
- packages_[p].reset();
- }
- }
-
- for (size_t p = 0; p < packages_.size(); p++) {
- const Package *package = o.packages_[p].get();
- if (package == nullptr) {
- continue;
- }
-
- for (size_t t = 0; t < package->types.size(); t++) {
- const ThemeType *type = package->types[t].get();
- if (type == nullptr) {
+ entries_.clear();
+
+ for (const auto& entry : source.entries_) {
+ bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE
+ || entry.value.dataType == Res_value::TYPE_REFERENCE
+ || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
+ || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE)
+ && entry.value.data != 0x0;
+
+ // If the attribute value represents an attribute or reference, the package id of the
+ // value needs to be rewritten to the package id of the value in the destination.
+ uint32_t attribute_data = entry.value.data;
+ if (is_reference) {
+ // Determine the package id of the reference in the destination AssetManager.
+ auto value_package_map = src_asset_cookie_id_map.find(entry.cookie);
+ if (value_package_map == src_asset_cookie_id_map.end()) {
continue;
}
- for (size_t e = 0; e < type->entry_count; e++) {
- const ThemeEntry &entry = type->entries[e];
- if (entry.value.dataType == Res_value::TYPE_NULL &&
- entry.value.data != Res_value::DATA_NULL_EMPTY) {
- continue;
- }
-
- bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE
- || entry.value.dataType == Res_value::TYPE_REFERENCE
- || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
- || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE)
- && entry.value.data != 0x0;
-
- // If the attribute value represents an attribute or reference, the package id of the
- // value needs to be rewritten to the package id of the value in the destination.
- uint32_t attribute_data = entry.value.data;
- if (is_reference) {
- // Determine the package id of the reference in the destination AssetManager.
- auto value_package_map = src_asset_cookie_id_map.find(entry.cookie);
- if (value_package_map == src_asset_cookie_id_map.end()) {
- continue;
- }
-
- auto value_dest_package = value_package_map->second.find(
- get_package_id(entry.value.data));
- if (value_dest_package == value_package_map->second.end()) {
- continue;
- }
-
- attribute_data = fix_package_id(entry.value.data, value_dest_package->second);
- }
-
- // Find the cookie of the value in the destination. If the source apk is not loaded in the
- // destination, only copy resources that do not reference resources in the source.
- ApkAssetsCookie data_dest_cookie;
- auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
- if (value_dest_cookie != src_to_dest_asset_cookies.end()) {
- data_dest_cookie = value_dest_cookie->second;
- } else {
- if (is_reference || entry.value.dataType == Res_value::TYPE_STRING) {
- continue;
- } else {
- data_dest_cookie = 0x0;
- }
- }
+ auto value_dest_package = value_package_map->second.find(
+ get_package_id(entry.value.data));
+ if (value_dest_package == value_package_map->second.end()) {
+ continue;
+ }
- // The package id of the attribute needs to be rewritten to the package id of the
- // attribute in the destination.
- int attribute_dest_package_id = p;
- if (attribute_dest_package_id != 0x01) {
- // Find the cookie of the attribute resource id in the source AssetManager
- base::expected<FindEntryResult, NullOrIOError> attribute_entry_result =
- o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ ,
- true /* stop_at_first_match */,
- true /* ignore_configuration */);
- if (UNLIKELY(IsIOError(attribute_entry_result))) {
- return base::unexpected(GetIOError(attribute_entry_result.error()));
- }
- if (!attribute_entry_result.has_value()) {
- continue;
- }
-
- // Determine the package id of the attribute in the destination AssetManager.
- auto attribute_package_map = src_asset_cookie_id_map.find(
- attribute_entry_result->cookie);
- if (attribute_package_map == src_asset_cookie_id_map.end()) {
- continue;
- }
- auto attribute_dest_package = attribute_package_map->second.find(
- attribute_dest_package_id);
- if (attribute_dest_package == attribute_package_map->second.end()) {
- continue;
- }
- attribute_dest_package_id = attribute_dest_package->second;
- }
+ attribute_data = fix_package_id(entry.value.data, value_dest_package->second);
+ }
- // Lazily instantiate the destination package.
- std::unique_ptr<Package>& dest_package = packages_[attribute_dest_package_id];
- if (dest_package == nullptr) {
- dest_package.reset(new Package());
- }
+ // Find the cookie of the value in the destination. If the source apk is not loaded in the
+ // destination, only copy resources that do not reference resources in the source.
+ ApkAssetsCookie data_dest_cookie;
+ auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
+ if (value_dest_cookie != src_to_dest_asset_cookies.end()) {
+ data_dest_cookie = value_dest_cookie->second;
+ } else {
+ if (is_reference || entry.value.dataType == Res_value::TYPE_STRING) {
+ continue;
+ } else {
+ data_dest_cookie = 0x0;
+ }
+ }
- // Lazily instantiate and resize the destination type.
- util::unique_cptr<ThemeType>& dest_type = dest_package->types[t];
- if (dest_type == nullptr || dest_type->entry_count < type->entry_count) {
- const size_t type_alloc_size = sizeof(ThemeType)
- + (type->entry_count * sizeof(ThemeEntry));
- void* dest_data = malloc(type_alloc_size);
- memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry));
-
- // Copy the existing destination type values if the type is resized.
- if (dest_type != nullptr) {
- memcpy(dest_data, type, sizeof(ThemeType)
- + (dest_type->entry_count * sizeof(ThemeEntry)));
- }
-
- dest_type.reset(reinterpret_cast<ThemeType *>(dest_data));
- dest_type->entry_count = type->entry_count;
- }
+ // The package id of the attribute needs to be rewritten to the package id of the
+ // attribute in the destination.
+ int attribute_dest_package_id = get_package_id(entry.attr_res_id);
+ if (attribute_dest_package_id != 0x01) {
+ // Find the cookie of the attribute resource id in the source AssetManager
+ base::expected<FindEntryResult, NullOrIOError> attribute_entry_result =
+ source.asset_manager_->FindEntry(entry.attr_res_id, 0 /* density_override */ ,
+ true /* stop_at_first_match */,
+ true /* ignore_configuration */);
+ if (UNLIKELY(IsIOError(attribute_entry_result))) {
+ return base::unexpected(GetIOError(attribute_entry_result.error()));
+ }
+ if (!attribute_entry_result.has_value()) {
+ continue;
+ }
- dest_type->entries[e].cookie = data_dest_cookie;
- dest_type->entries[e].value.dataType = entry.value.dataType;
- dest_type->entries[e].value.data = attribute_data;
- dest_type->entries[e].type_spec_flags = entry.type_spec_flags;
+ // Determine the package id of the attribute in the destination AssetManager.
+ auto attribute_package_map = src_asset_cookie_id_map.find(
+ attribute_entry_result->cookie);
+ if (attribute_package_map == src_asset_cookie_id_map.end()) {
+ continue;
+ }
+ auto attribute_dest_package = attribute_package_map->second.find(
+ attribute_dest_package_id);
+ if (attribute_dest_package == attribute_package_map->second.end()) {
+ continue;
}
+ attribute_dest_package_id = attribute_dest_package->second;
}
+
+ auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(entry.attr_res_id),
+ get_entry_id(entry.attr_res_id));
+ Theme::Entry new_entry{dest_attr_id, data_dest_cookie, entry.type_spec_flags,
+ Res_value{.dataType = entry.value.dataType,
+ .data = attribute_data}};
+
+ // Since the entries were cleared, the attribute resource id has yet been mapped to any value.
+ auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), dest_attr_id,
+ ThemeEntryKeyComparer{});
+ entries_.insert(entry_it, new_entry);
}
}
return {};
@@ -1730,31 +1611,10 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& o) {
void Theme::Dump() const {
LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
-
- for (int p = 0; p < packages_.size(); p++) {
- auto& package = packages_[p];
- if (package == nullptr) {
- continue;
- }
-
- for (int t = 0; t < package->types.size(); t++) {
- auto& type = package->types[t];
- if (type == nullptr) {
- continue;
- }
-
- for (int e = 0; e < type->entry_count; e++) {
- auto& entry = type->entries[e];
- if (entry.value.dataType == Res_value::TYPE_NULL &&
- entry.value.data != Res_value::DATA_NULL_EMPTY) {
- continue;
- }
-
- LOG(INFO) << base::StringPrintf(" entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
- make_resid(p, t, e), entry.value.data,
- entry.value.dataType, entry.cookie);
- }
- }
+ for (auto& entry : entries_) {
+ LOG(INFO) << base::StringPrintf(" entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
+ entry.attr_res_id, entry.value.data, entry.value.dataType,
+ entry.cookie);
}
}
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index df3abf63323a..7d01395bbbbc 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -508,13 +508,18 @@ class Theme {
// data failed.
base::expected<std::monostate, NullOrIOError> ApplyStyle(uint32_t resid, bool force = false);
- // Sets this Theme to be a copy of `other` if `other` has the same AssetManager as this Theme.
+ // Clears the existing theme, sets the new asset manager to use for this theme, and applies the
+ // styles in `style_ids` through repeated invocations of `ApplyStyle`.
+ void Rebase(AssetManager2* am, const uint32_t* style_ids, const uint8_t* force,
+ size_t style_count);
+
+ // Sets this Theme to be a copy of `source` if `source` has the same AssetManager as this Theme.
//
- // If `other` does not have the same AssetManager as this theme, only attributes from ApkAssets
+ // If `source` does not have the same AssetManager as this theme, only attributes from ApkAssets
// loaded into both AssetManagers will be copied to this theme.
//
// Returns an I/O error if reading resource data failed.
- base::expected<std::monostate, IOError> SetTo(const Theme& other);
+ base::expected<std::monostate, IOError> SetTo(const Theme& source);
void Clear();
@@ -546,20 +551,16 @@ class Theme {
void Dump() const;
+ struct Entry;
private:
DISALLOW_COPY_AND_ASSIGN(Theme);
- // Called by AssetManager2.
explicit Theme(AssetManager2* asset_manager);
- AssetManager2* asset_manager_;
+ AssetManager2* asset_manager_ = nullptr;
uint32_t type_spec_flags_ = 0u;
- // Defined in the cpp.
- struct Package;
-
- constexpr static size_t kPackageCount = std::numeric_limits<uint8_t>::max() + 1;
- std::array<std::unique_ptr<Package>, kPackageCount> packages_;
+ std::vector<Entry> entries_;
};
inline const ResolvedBag::Entry* begin(const ResolvedBag* bag) {
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index f658735da515..77114f273d3d 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -251,6 +251,80 @@ TEST_F(ThemeTest, CopyThemeSameAssetManager) {
EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
+TEST_F(ThemeTest, ThemeRebase) {
+ AssetManager2 am;
+ am.SetApkAssets({style_assets_.get()});
+
+ AssetManager2 am_night;
+ am_night.SetApkAssets({style_assets_.get()});
+
+ ResTable_config night{};
+ night.uiMode = ResTable_config::UI_MODE_NIGHT_YES;
+ night.version = 8u;
+ am_night.SetConfiguration(night);
+
+ auto theme = am.NewTheme();
+ {
+ const uint32_t styles[] = {app::R::style::StyleOne, app::R::style::StyleDayNight};
+ const uint8_t force[] = {true, true};
+ theme->Rebase(&am, styles, force, arraysize(styles));
+ }
+
+ // attr_one in StyleDayNight force overrides StyleOne. attr_one is defined in the StyleOne.
+ auto value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(10u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC | ResTable_config::CONFIG_UI_MODE |
+ ResTable_config::CONFIG_VERSION), value->flags);
+
+ // attr_two is defined in the StyleOne.
+ value = theme->GetAttribute(app::R::attr::attr_two);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(2u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
+
+ {
+ const uint32_t styles[] = {app::R::style::StyleOne, app::R::style::StyleDayNight};
+ const uint8_t force[] = {false, false};
+ theme->Rebase(&am, styles, force, arraysize(styles));
+ }
+
+ // attr_one in StyleDayNight does not override StyleOne because `force` is false.
+ value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
+
+ // attr_two is defined in the StyleOne.
+ value = theme->GetAttribute(app::R::attr::attr_two);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(2u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
+
+ {
+ const uint32_t styles[] = {app::R::style::StyleOne, app::R::style::StyleDayNight};
+ const uint8_t force[] = {false, true};
+ theme->Rebase(&am_night, styles, force, arraysize(styles));
+ }
+
+ // attr_one is defined in the StyleDayNight.
+ value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(100u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC | ResTable_config::CONFIG_UI_MODE |
+ ResTable_config::CONFIG_VERSION), value->flags);
+
+ // attr_two is now not here.
+ value = theme->GetAttribute(app::R::attr::attr_two);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(2u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
+}
+
TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
AssetManager2 assetmanager_dst;
assetmanager_dst.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(),
diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h
index f11486fe924a..393a20780c79 100644
--- a/libs/androidfw/tests/data/styles/R.h
+++ b/libs/androidfw/tests/data/styles/R.h
@@ -52,6 +52,7 @@ struct R {
StyleFive = 0x7f020004u,
StyleSix = 0x7f020005u,
StyleSeven = 0x7f020006u,
+ StyleDayNight = 0x7f020007u,
};
};
};
diff --git a/libs/androidfw/tests/data/styles/res/values/styles.xml b/libs/androidfw/tests/data/styles/res/values/styles.xml
index 06774a8a6005..fe46a3fa90c8 100644
--- a/libs/androidfw/tests/data/styles/res/values/styles.xml
+++ b/libs/androidfw/tests/data/styles/res/values/styles.xml
@@ -89,4 +89,9 @@
<item name="android:theme">@empty</item>
</style>
+ <public type="style" name="StyleDayNight" id="0x7f020007" />
+ <style name="StyleDayNight">
+ <item name="attr_one">10</item>
+ </style>
+
</resources>
diff --git a/libs/androidfw/tests/data/styles/styles.apk b/libs/androidfw/tests/data/styles/styles.apk
index 92e9bf90101e..91cd6546c336 100644
--- a/libs/androidfw/tests/data/styles/styles.apk
+++ b/libs/androidfw/tests/data/styles/styles.apk
Binary files differ
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 8a8b4181bd94..d8735ce57b65 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -275,6 +275,14 @@ CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap
return copyResult;
}
+CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, SkBitmap* bitmap) {
+ Rect srcRect;
+ Matrix4 transform;
+ transform.loadScale(1, -1, 1);
+ transform.translate(0, -1);
+ return copyImageInto(image, transform, srcRect, bitmap);
+}
+
CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform,
const Rect& srcRect, SkBitmap* bitmap) {
ATRACE_CALL();
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index 4cb4bd8510ab..da252695dd3b 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -50,6 +50,7 @@ public:
CopyResult copySurfaceInto(ANativeWindow* window, const Rect& srcRect, SkBitmap* bitmap);
CopyResult copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap);
+ CopyResult copyImageInto(const sk_sp<SkImage>& image, SkBitmap* bitmap);
CopyResult copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
diff --git a/libs/hwui/jni/Picture.h b/libs/hwui/jni/Picture.h
index 536f651473a9..87ba3978a780 100644
--- a/libs/hwui/jni/Picture.h
+++ b/libs/hwui/jni/Picture.h
@@ -38,6 +38,7 @@ class Picture {
public:
explicit Picture(const Picture* src = NULL);
explicit Picture(sk_sp<SkPicture>&& src);
+ virtual ~Picture() = default;
Canvas* beginRecording(int width, int height);
@@ -49,7 +50,7 @@ public:
static Picture* CreateFromStream(SkStream* stream);
- void serialize(SkWStream* stream) const;
+ virtual void serialize(SkWStream* stream) const;
void draw(Canvas* canvas);
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 4289c455453e..602c32a966d3 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -23,6 +23,8 @@
#include <Picture.h>
#include <Properties.h>
#include <RootRenderNode.h>
+#include <SkImagePriv.h>
+#include <SkSerialProcs.h>
#include <dlfcn.h>
#include <gui/TraceUtils.h>
#include <inttypes.h>
@@ -35,6 +37,7 @@
#include <renderthread/RenderProxy.h>
#include <renderthread/RenderTask.h>
#include <renderthread/RenderThread.h>
+#include <src/image/SkImage_Base.h>
#include <thread/CommonPool.h>
#include <utils/Color.h>
#include <utils/RefBase.h>
@@ -497,6 +500,108 @@ private:
jobject mObject;
};
+using TextureMap = std::unordered_map<uint32_t, sk_sp<SkImage>>;
+
+struct PictureCaptureState {
+ // Each frame we move from the active map to the previous map, essentially an LRU of 1 frame
+ // This avoids repeated readbacks of the same image, but avoids artificially extending the
+ // lifetime of any particular image.
+ TextureMap mActiveMap;
+ TextureMap mPreviousActiveMap;
+};
+
+// TODO: This & Multi-SKP & Single-SKP should all be de-duped into
+// a single "make a SkPicture serailizable-safe" utility somewhere
+class PictureWrapper : public Picture {
+public:
+ PictureWrapper(sk_sp<SkPicture>&& src, const std::shared_ptr<PictureCaptureState>& state)
+ : Picture(), mPicture(std::move(src)) {
+ ATRACE_NAME("Preparing SKP for capture");
+ // Move the active to previous active
+ state->mPreviousActiveMap = std::move(state->mActiveMap);
+ state->mActiveMap.clear();
+ SkSerialProcs tempProc;
+ tempProc.fImageCtx = state.get();
+ tempProc.fImageProc = collectNonTextureImagesProc;
+ auto ns = SkNullWStream();
+ mPicture->serialize(&ns, &tempProc);
+ state->mPreviousActiveMap.clear();
+
+ // Now snapshot a copy of the active map so this PictureWrapper becomes self-sufficient
+ mTextureMap = state->mActiveMap;
+ }
+
+ static sk_sp<SkImage> imageForCache(SkImage* img) {
+ const SkBitmap* bitmap = as_IB(img)->onPeekBitmap();
+ // This is a mutable bitmap pretending to be an immutable SkImage. As we're going to
+ // actually cross thread boundaries here, make a copy so it's immutable proper
+ if (bitmap && !bitmap->isImmutable()) {
+ ATRACE_NAME("Copying mutable bitmap");
+ return SkImage::MakeFromBitmap(*bitmap);
+ }
+ if (img->isTextureBacked()) {
+ ATRACE_NAME("Readback of texture image");
+ return img->makeNonTextureImage();
+ }
+ SkPixmap pm;
+ if (img->isLazyGenerated() && !img->peekPixels(&pm)) {
+ ATRACE_NAME("Readback of HW bitmap");
+ // This is a hardware bitmap probably
+ SkBitmap bm;
+ if (!bm.tryAllocPixels(img->imageInfo())) {
+ // Failed to allocate, just see what happens
+ return sk_ref_sp(img);
+ }
+ if (RenderProxy::copyImageInto(sk_ref_sp(img), &bm)) {
+ // Failed to readback
+ return sk_ref_sp(img);
+ }
+ bm.setImmutable();
+ return SkMakeImageFromRasterBitmap(bm, kNever_SkCopyPixelsMode);
+ }
+ return sk_ref_sp(img);
+ }
+
+ static sk_sp<SkData> collectNonTextureImagesProc(SkImage* img, void* ctx) {
+ PictureCaptureState* context = reinterpret_cast<PictureCaptureState*>(ctx);
+ const uint32_t originalId = img->uniqueID();
+ auto it = context->mActiveMap.find(originalId);
+ if (it == context->mActiveMap.end()) {
+ auto pit = context->mPreviousActiveMap.find(originalId);
+ if (pit == context->mPreviousActiveMap.end()) {
+ context->mActiveMap[originalId] = imageForCache(img);
+ } else {
+ context->mActiveMap[originalId] = pit->second;
+ }
+ }
+ return SkData::MakeEmpty();
+ }
+
+ static sk_sp<SkData> serializeImage(SkImage* img, void* ctx) {
+ PictureWrapper* context = reinterpret_cast<PictureWrapper*>(ctx);
+ const uint32_t id = img->uniqueID();
+ auto iter = context->mTextureMap.find(id);
+ if (iter != context->mTextureMap.end()) {
+ img = iter->second.get();
+ }
+ return img->encodeToData();
+ }
+
+ void serialize(SkWStream* stream) const override {
+ SkSerialProcs procs;
+ procs.fImageProc = serializeImage;
+ procs.fImageCtx = const_cast<PictureWrapper*>(this);
+ procs.fTypefaceProc = [](SkTypeface* tf, void* ctx) {
+ return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
+ };
+ mPicture->serialize(stream, &procs);
+ }
+
+private:
+ sk_sp<SkPicture> mPicture;
+ TextureMap mTextureMap;
+};
+
static void android_view_ThreadedRenderer_setPictureCapturedCallbackJNI(JNIEnv* env,
jobject clazz, jlong proxyPtr, jobject pictureCallback) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -507,9 +612,11 @@ static void android_view_ThreadedRenderer_setPictureCapturedCallbackJNI(JNIEnv*
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm,
env->NewGlobalRef(pictureCallback));
- proxy->setPictureCapturedCallback([globalCallbackRef](sk_sp<SkPicture>&& picture) {
+ auto pictureState = std::make_shared<PictureCaptureState>();
+ proxy->setPictureCapturedCallback([globalCallbackRef,
+ pictureState](sk_sp<SkPicture>&& picture) {
JNIEnv* env = getenv(globalCallbackRef->vm());
- Picture* wrapper = new Picture{std::move(picture)};
+ Picture* wrapper = new PictureWrapper{std::move(picture), pictureState};
env->CallStaticVoidMethod(gHardwareRenderer.clazz,
gHardwareRenderer.invokePictureCapturedCallback,
static_cast<jlong>(reinterpret_cast<intptr_t>(wrapper)),
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index a78cd8316624..9bca4df577c9 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -75,7 +75,9 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con
bool opaque, const LightInfo& lightInfo,
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler) {
- mEglManager.damageFrame(frame, dirty);
+ if (!isCapturingSkp()) {
+ mEglManager.damageFrame(frame, dirty);
+ }
SkColorType colorType = getSurfaceColorType();
// setup surface for fbo0
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 039b0f9a6e9a..5462623e75ff 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -420,7 +420,7 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
procs.fTypefaceProc = [](SkTypeface* tf, void* ctx){
return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
};
- auto data = picture->serialize();
+ auto data = picture->serialize(&procs);
savePictureAsync(data, mCapturedFile);
mCaptureSequence = 0;
mCaptureMode = CaptureMode::None;
@@ -470,8 +470,7 @@ void SkiaPipeline::renderFrameImpl(const SkRect& clip,
const SkMatrix& preTransform) {
SkAutoCanvasRestore saver(canvas, true);
auto clipRestriction = preTransform.mapRect(clip).roundOut();
- if (CC_UNLIKELY(mCaptureMode == CaptureMode::SingleFrameSKP
- || mCaptureMode == CaptureMode::MultiFrameSKP)) {
+ if (CC_UNLIKELY(isCapturingSkp())) {
canvas->drawAnnotation(SkRect::Make(clipRestriction), "AndroidDeviceClipRestriction",
nullptr);
} else {
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 46580358aaf5..bc8a5659dd83 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -80,6 +80,8 @@ protected:
SkColorType mSurfaceColorType;
sk_sp<SkColorSpace> mSurfaceColorSpace;
+ bool isCapturingSkp() const { return mCaptureMode != CaptureMode::None; }
+
private:
void renderFrameImpl(const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index ac19a153b6fb..6fd644bfa28e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -390,6 +390,17 @@ int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {
}
}
+int RenderProxy::copyImageInto(const sk_sp<SkImage>& image, SkBitmap* bitmap) {
+ RenderThread& thread = RenderThread::getInstance();
+ if (gettid() == thread.getTid()) {
+ // TODO: fix everything that hits this. We should never be triggering a readback ourselves.
+ return (int)thread.readback().copyImageInto(image, bitmap);
+ } else {
+ return thread.queue().runSync(
+ [&]() -> int { return (int)thread.readback().copyImageInto(image, bitmap); });
+ }
+}
+
void RenderProxy::disableVsync() {
Properties::disableVsync = true;
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 0681dc5e16be..6d80949a4eba 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -136,6 +136,7 @@ public:
static void prepareToDraw(Bitmap& bitmap);
static int copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap);
+ static int copyImageInto(const sk_sp<SkImage>& image, SkBitmap* bitmap);
static void disableVsync();
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 5a718330d68f..f70149111116 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -425,27 +425,38 @@ Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) {
semaphoreInfo.flags = 0;
VkSemaphore semaphore;
VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
- LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to create import semaphore, err: %d",
- err);
-
- VkImportSemaphoreFdInfoKHR importInfo;
- importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
- importInfo.pNext = nullptr;
- importInfo.semaphore = semaphore;
- importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
- importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- importInfo.fd = fence_clone;
-
- err = mImportSemaphoreFdKHR(mDevice, &importInfo);
- LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to import semaphore, err: %d", err);
-
- GrBackendSemaphore backendSemaphore;
- backendSemaphore.initVulkan(semaphore);
- bufferInfo->skSurface->wait(1, &backendSemaphore);
- // The following flush blocks the GPU immediately instead of waiting for other
- // drawing ops. It seems dequeue_fence is not respected otherwise.
- // TODO: remove the flush after finding why backendSemaphore is not working.
- bufferInfo->skSurface->flushAndSubmit();
+ if (err != VK_SUCCESS) {
+ ALOGE("Failed to create import semaphore, err: %d", err);
+ close(fence_clone);
+ sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
+ } else {
+ VkImportSemaphoreFdInfoKHR importInfo;
+ importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+ importInfo.pNext = nullptr;
+ importInfo.semaphore = semaphore;
+ importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+ importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+ importInfo.fd = fence_clone;
+
+ err = mImportSemaphoreFdKHR(mDevice, &importInfo);
+ if (err != VK_SUCCESS) {
+ ALOGE("Failed to import semaphore, err: %d", err);
+ mDestroySemaphore(mDevice, semaphore, nullptr);
+ close(fence_clone);
+ sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
+ } else {
+ GrBackendSemaphore backendSemaphore;
+ backendSemaphore.initVulkan(semaphore);
+ // Skia will take ownership of the VkSemaphore and delete it once the wait
+ // has finished. The VkSemaphore also owns the imported fd, so it will
+ // close the fd when it is deleted.
+ bufferInfo->skSurface->wait(1, &backendSemaphore);
+ // The following flush blocks the GPU immediately instead of waiting for
+ // other drawing ops. It seems dequeue_fence is not respected otherwise.
+ // TODO: remove the flush after finding why backendSemaphore is not working.
+ bufferInfo->skSurface->flushAndSubmit();
+ }
+ }
}
}
}
@@ -621,6 +632,7 @@ status_t VulkanManager::fenceWait(int fence, GrDirectContext* grContext) {
VkSemaphore semaphore;
VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
if (VK_SUCCESS != err) {
+ close(fenceFd);
ALOGE("Failed to create import semaphore, err: %d", err);
return UNKNOWN_ERROR;
}
@@ -635,6 +647,7 @@ status_t VulkanManager::fenceWait(int fence, GrDirectContext* grContext) {
err = mImportSemaphoreFdKHR(mDevice, &importInfo);
if (VK_SUCCESS != err) {
mDestroySemaphore(mDevice, semaphore, nullptr);
+ close(fenceFd);
ALOGE("Failed to import semaphore, err: %d", err);
return UNKNOWN_ERROR;
}
@@ -642,7 +655,8 @@ status_t VulkanManager::fenceWait(int fence, GrDirectContext* grContext) {
GrBackendSemaphore beSemaphore;
beSemaphore.initVulkan(semaphore);
- // Skia takes ownership of the semaphore and will delete it once the wait has finished.
+ // Skia will take ownership of the VkSemaphore and delete it once the wait has finished. The
+ // VkSemaphore also owns the imported fd, so it will close the fd when it is deleted.
grContext->wait(1, &beSemaphore);
grContext->flushAndSubmit();
diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp
index 50e0d336f981..6ef074090df8 100644
--- a/media/jni/soundpool/Sound.cpp
+++ b/media/jni/soundpool/Sound.cpp
@@ -214,7 +214,7 @@ status_t Sound::doLoad()
} else if (sampleRate > kMaxSampleRate) {
ALOGE("%s: sample rate (%u) out of range", __func__, sampleRate);
status = BAD_VALUE;
- } else if (channelCount < 1 || channelCount > FCC_8) {
+ } else if (channelCount < 1 || channelCount > FCC_LIMIT) {
ALOGE("%s: sample channel count (%d) out of range", __func__, channelCount);
status = BAD_VALUE;
} else {
diff --git a/packages/DynamicSystemInstallationService/res/values-uz/strings.xml b/packages/DynamicSystemInstallationService/res/values-uz/strings.xml
index 5597fb5e0e51..a34ac0007886 100644
--- a/packages/DynamicSystemInstallationService/res/values-uz/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-uz/strings.xml
@@ -8,7 +8,7 @@
<string name="notification_image_validation_failed" msgid="2720357826403917016">"Disk tasviri tekshiruvi amalga oshmadi. Oʻrnatishni bekor qiling."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Hozirda dinamik tizim ishga tushirilgan. Asl Android versiyasidan foydlanish uchun qayta ishga tushiring."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Bekor qilish"</string>
- <string name="notification_action_discard" msgid="1817481003134947493">"Bekor qilish"</string>
+ <string name="notification_action_discard" msgid="1817481003134947493">"Rad etish"</string>
<string name="notification_action_reboot_to_dynsystem" msgid="4015817159115912479">"Boshidan"</string>
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Boshidan"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamik tizim bekor qilindi"</string>
diff --git a/packages/PrintSpooler/res/values-az/strings.xml b/packages/PrintSpooler/res/values-az/strings.xml
index 887434b4409f..fae4736f29e9 100644
--- a/packages/PrintSpooler/res/values-az/strings.xml
+++ b/packages/PrintSpooler/res/values-az/strings.xml
@@ -17,7 +17,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="4469836075319831821">"Çap Spuler"</string>
- <string name="more_options_button" msgid="2243228396432556771">"Digər variantlar"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Digər seçimlər"</string>
<string name="label_destination" msgid="9132510997381599275">"Hədəf"</string>
<string name="label_copies" msgid="3634531042822968308">"Surətlər"</string>
<string name="label_copies_summary" msgid="3861966063536529540">"Nüsxələr:"</string>
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_progress_horizontal.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_progress_horizontal.xml
new file mode 100644
index 000000000000..a4c780bc20de
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_progress_horizontal.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@android:id/background">
+ <shape>
+ <corners android:radius="8dp" />
+ <solid android:color="@color/settingslib_colorSurfaceVariant" />
+ </shape>
+ </item>
+
+ <item
+ android:id="@android:id/progress">
+ <clip>
+ <shape>
+ <corners android:radius="8dp" />
+ <solid android:color="?android:attr/textColorPrimary" />
+ </shape>
+ </clip>
+ </item>
+</layer-list>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
index 426a2ba447f2..69975cd2dad5 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -31,4 +31,6 @@
<color name="settingslib_dialog_background">@android:color/system_neutral1_800</color>
<!-- Dialog error color. -->
<color name="settingslib_dialog_colorError">#f28b82</color> <!-- Red 300 -->
+
+ <color name="settingslib_colorSurfaceVariant">@android:color/system_neutral1_700</color>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
index fcba6bd95cb6..aed6338495f0 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -37,4 +37,6 @@
<color name="settingslib_dialog_background">@android:color/system_neutral1_800</color>
<!-- Dialog error color. -->
<color name="settingslib_dialog_colorError">#d93025</color> <!-- Red 600 -->
+
+ <color name="settingslib_colorSurfaceVariant">@android:color/system_neutral2_100</color>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index e3a023995e76..9610c9443184 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -28,4 +28,10 @@
<item name="android:track">@drawable/settingslib_switch_track</item>
<item name="android:thumb">@drawable/settingslib_switch_thumb</item>
</style>
+
+ <style name="HorizontalProgressBar.SettingsLib"
+ parent="android:style/Widget.Material.ProgressBar.Horizontal">
+ <item name="android:progressDrawable">@drawable/settingslib_progress_horizontal</item>
+ <item name="android:scaleY">0.5</item>
+ </style>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
index b3378b201f4d..b5cf36881643 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
@@ -23,6 +23,7 @@
<item name="android:listPreferredItemPaddingEnd">16dp</item>
<item name="preferenceTheme">@style/PreferenceTheme.SettingsLib</item>
<item name="android:switchStyle">@style/Switch.SettingsLib</item>
+ <item name="android:progressBarStyleHorizontal">@style/HorizontalProgressBar.SettingsLib</item>
</style>
<!-- Using in SubSettings page including injected settings page -->
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index c9c3db8a2e27..eb8196176034 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -75,5 +75,6 @@ public class GlobalSettings {
Settings.Global.USER_DISABLED_HDR_FORMATS,
Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED,
Settings.Global.DEVICE_CONFIG_SYNC_DISABLED,
+ Settings.Global.POWER_BUTTON_LONG_PRESS,
};
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index f538875bf337..3297937e3e75 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -587,7 +587,6 @@ public class SettingsBackupTest {
Settings.Global.RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD,
Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT,
Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT,
- Settings.Global.POWER_BUTTON_LONG_PRESS,
Settings.Global.POWER_BUTTON_VERY_LONG_PRESS,
Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, // Temporary for R beta
Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index bcb21d1d64ce..959b5ca56687 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -526,6 +526,9 @@
<!-- Permission required for CTS test - FontManagerTest -->
<uses-permission android:name="android.permission.UPDATE_FONTS" />
+ <!-- Permission required for Launcher testing - DigitalWellbeingToastTest -->
+ <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"/>
+
<!-- Permission required for hotword detection service CTS tests -->
<uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
<uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
diff --git a/packages/Shell/res/values-pa/strings.xml b/packages/Shell/res/values-pa/strings.xml
index d0c29055ecc1..daeac3cf0b04 100644
--- a/packages/Shell/res/values-pa/strings.xml
+++ b/packages/Shell/res/values-pa/strings.xml
@@ -16,7 +16,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="3701846017049540910">"ਸ਼ੈਲ"</string>
+ <string name="app_label" msgid="3701846017049540910">"ਸ਼ੈੱਲ"</string>
<string name="bugreport_notification_channel" msgid="2574150205913861141">"ਬੱਗ ਰਿਪੋਰਟਾਂ"</string>
<string name="bugreport_in_progress_title" msgid="4311705936714972757">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਸਿਰਜੀ ਜਾ ਰਹੀ ਹੈ"</string>
<string name="bugreport_finished_title" msgid="4429132808670114081">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਕੈਪਚਰ ਕੀਤੀ ਗਈ"</string>
diff --git a/packages/SystemUI/res/drawable/screenshot_border.xml b/packages/SystemUI/res/drawable/screenshot_border.xml
index bb858dbc795a..c1accdc7063a 100644
--- a/packages/SystemUI/res/drawable/screenshot_border.xml
+++ b/packages/SystemUI/res/drawable/screenshot_border.xml
@@ -19,5 +19,5 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<solid android:color="?androidprv:attr/colorSurface"/>
- <corners android:radius="20dp"/>
+ <corners android:radius="24dp"/>
</shape>
diff --git a/packages/SystemUI/res/drawable/screenshot_edit_background.xml b/packages/SystemUI/res/drawable/screenshot_edit_background.xml
index 5c3c12c572f6..ff5c62e1600b 100644
--- a/packages/SystemUI/res/drawable/screenshot_edit_background.xml
+++ b/packages/SystemUI/res/drawable/screenshot_edit_background.xml
@@ -20,7 +20,7 @@
android:color="?android:textColorPrimary">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorAccentSecondary"/>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
<corners android:radius="16dp"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/screenshot_save_background.xml b/packages/SystemUI/res/drawable/screenshot_save_background.xml
index cfd2dc214477..b61b28ed1d9e 100644
--- a/packages/SystemUI/res/drawable/screenshot_save_background.xml
+++ b/packages/SystemUI/res/drawable/screenshot_save_background.xml
@@ -20,7 +20,7 @@
android:color="?android:textColorPrimary">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorAccentSecondary"/>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
<corners android:radius="20dp"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 5bd181c82492..93bd58113bc2 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -21,6 +21,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
+ android:id="@+id/screenshot_scrolling_scrim"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"/>
+ <ImageView
android:id="@+id/global_screenshot_actions_background"
android:layout_height="@dimen/screenshot_bg_protection_height"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index 60dbaf97b7f7..ba46edced03c 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -71,7 +71,7 @@
android:background="@drawable/screenshot_border"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/screenshot_preview_end"
+ app:layout_constraintEnd_toEndOf="@+id/screenshot_preview_end"
app:layout_constraintTop_toTopOf="@+id/screenshot_preview_top"/>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/screenshot_preview_end"
@@ -91,8 +91,7 @@
android:id="@+id/global_screenshot_preview"
android:visibility="invisible"
android:layout_width="@dimen/global_screenshot_x_scale"
- android:layout_marginStart="4dp"
- android:layout_marginBottom="4dp"
+ android:layout_margin="4dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:elevation="@dimen/screenshot_preview_elevation"
@@ -101,7 +100,9 @@
android:background="@drawable/screenshot_preview_background"
android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="@+id/global_screenshot_preview_border"
- app:layout_constraintStart_toStartOf="@+id/global_screenshot_preview_border">
+ app:layout_constraintStart_toStartOf="@+id/global_screenshot_preview_border"
+ app:layout_constraintEnd_toEndOf="@+id/global_screenshot_preview_border"
+ app:layout_constraintTop_toTopOf="@+id/global_screenshot_preview_border">
</ImageView>
<FrameLayout
android:id="@+id/global_screenshot_dismiss_button"
@@ -121,4 +122,12 @@
android:layout_margin="@dimen/screenshot_dismiss_button_margin"
android:src="@drawable/screenshot_cancel"/>
</FrameLayout>
+ <ImageView
+ android:id="@+id/screenshot_scrollable_preview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scaleType="matrix"
+ app:layout_constraintStart_toStartOf="@id/global_screenshot_preview"
+ app:layout_constraintTop_toTopOf="@id/global_screenshot_preview"
+ android:elevation="@dimen/screenshot_preview_elevation"/>
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index 8e30aecd6a27..8fb9aa63a5a3 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -62,6 +62,7 @@
android:paddingHorizontal="48dp"
android:paddingTop="8dp"
android:paddingBottom="42dp"
+ android:alpha="0"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@id/save"
@@ -72,6 +73,16 @@
tools:minHeight="100dp"
tools:minWidth="100dp" />
+ <ImageView
+ android:id="@+id/enter_transition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scaleType="matrix"
+ app:layout_constraintTop_toTopOf="@id/preview"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ android:transitionName="screenshot_preview_image"/>
+
<com.android.systemui.screenshot.CropView
android:id="@+id/crop_view"
android:layout_width="0px"
@@ -86,7 +97,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:handleThickness="@dimen/screenshot_crop_handle_thickness"
- app:handleColor="?androidprv:attr/colorAccentSecondary"
+ app:handleColor="?androidprv:attr/colorAccentPrimary"
app:scrimColor="@color/screenshot_crop_scrim"
tools:background="?android:colorBackground"
tools:minHeight="100dp"
diff --git a/packages/SystemUI/res/layout/people_space_placeholder_layout.xml b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
index abb771b98667..143c173998df 100644
--- a/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
+++ b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
@@ -34,7 +34,7 @@
<LinearLayout
android:orientation="vertical"
android:paddingEnd="20dp"
- android:gravity="bottom"
+ android:gravity="start|bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
diff --git a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
index 1086a1361366..25a11657a92d 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
@@ -113,7 +113,6 @@
android:id="@+id/name"
android:layout_gravity="start|center_vertical"
android:gravity="start|center_vertical"
- android:layout_weight="1"
android:text="@string/empty_user_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
@@ -124,8 +123,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
android:id="@+id/messages_count"
android:gravity="end"
+ android:layout_weight="1"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
index 9b6c92c71e5d..1112bcdbd14d 100644
--- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml
+++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
@@ -59,7 +59,7 @@
android:id="@+id/volume_drawer_vibrate"
android:layout_width="@dimen/volume_ringer_drawer_item_size"
android:layout_height="@dimen/volume_ringer_drawer_item_size"
- android:description="@string/volume_ringer_hint_vibrate"
+ android:contentDescription="@string/volume_ringer_hint_vibrate"
android:gravity="center">
<ImageView
@@ -76,7 +76,7 @@
android:id="@+id/volume_drawer_mute"
android:layout_width="@dimen/volume_ringer_drawer_item_size"
android:layout_height="@dimen/volume_ringer_drawer_item_size"
- android:description="@string/volume_ringer_hint_mute"
+ android:contentDescription="@string/volume_ringer_hint_mute"
android:gravity="center">
<ImageView
@@ -93,7 +93,7 @@
android:id="@+id/volume_drawer_normal"
android:layout_width="@dimen/volume_ringer_drawer_item_size"
android:layout_height="@dimen/volume_ringer_drawer_item_size"
- android:description="@string/volume_ringer_hint_unmute"
+ android:contentDescription="@string/volume_ringer_hint_unmute"
android:gravity="center">
<ImageView
@@ -117,7 +117,7 @@
android:layout_width="@dimen/volume_ringer_drawer_item_size"
android:layout_height="@dimen/volume_ringer_drawer_item_size"
android:layout_gravity="bottom|right"
- android:description="@string/volume_ringer_change"
+ android:contentDescription="@string/volume_ringer_change"
android:background="@drawable/volume_drawer_selection_bg">
<ImageView
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 551f246dbacb..040725e135fd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1236,7 +1236,7 @@
<!-- Blur radius on status bar window and power menu -->
<dimen name="min_window_blur_radius">1px</dimen>
- <dimen name="max_window_blur_radius">150px</dimen>
+ <dimen name="max_window_blur_radius">72px</dimen>
<!-- How much into a DisplayCutout's bounds we can go, on each side -->
<dimen name="display_cutout_margin_consumption">0px</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index 92af58eb9af4..08076c17dc3a 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -127,8 +127,10 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
@Override
public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {
+ // Strong auth will force the bouncer regardless of a successful face auth
if (biometricSourceType == BiometricSourceType.FACE
- && mBypassController.canBypass()) {
+ && mBypassController.canBypass()
+ && !mKeyguardUpdateMonitor.userNeedsStrongAuth()) {
mView.animateDisappear();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index dd339abb3a40..f975a804ca80 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -405,9 +405,8 @@ public class UdfpsController implements DozeReceiver {
? event.getPointerId(0)
: event.findPointerIndex(mActivePointerId);
if (idx == event.getActionIndex()) {
- final float x = event.getX(idx);
- final float y = event.getY(idx);
- if (isWithinSensorArea(udfpsView, x, y, fromUdfpsView)) {
+ if (isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx),
+ fromUdfpsView)) {
if (mVelocityTracker == null) {
// touches could be injected, so the velocity tracker may not have
// been initialized (via ACTION_DOWN).
@@ -427,7 +426,8 @@ public class UdfpsController implements DozeReceiver {
final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime;
if (!isIlluminationRequested && !mGoodCaptureReceived &&
!exceedsVelocityThreshold) {
- onFingerDown((int) x, (int) y, minor, major);
+ onFingerDown((int) event.getRawX(), (int) event.getRawY(), minor,
+ major);
Log.v(TAG, "onTouch | finger down: " + touchInfo);
mTouchLogTime = SystemClock.elapsedRealtime();
mPowerManager.userActivity(SystemClock.uptimeMillis(),
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 af7089296bca..567d0cb3e6cb 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -422,8 +422,12 @@ class ControlsUiControllerImpl @Inject constructor (
// add spacers if necessary to keep control size consistent
val mod = selectedStructure.controls.size % maxColumns
var spacersToAdd = if (mod == 0) 0 else maxColumns - mod
+ val margin = context.resources.getDimensionPixelSize(R.dimen.control_spacing)
while (spacersToAdd > 0) {
- lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
+ val lp = LinearLayout.LayoutParams(0, 0, 1f).apply {
+ setMarginStart(margin)
+ }
+ lastRow.addView(Space(context), lp)
spacersToAdd--
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 72d382ac0799..06817b9e314e 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -348,7 +348,7 @@ public class PeopleTileViewHelper {
if (mWidth >= getSizeInDp(R.dimen.required_width_for_medium)) {
int spaceAvailableForPadding =
mHeight - (getSizeInDp(R.dimen.avatar_size_for_medium)
- + getLineHeightFromResource(
+ + 4 + getLineHeightFromResource(
R.dimen.name_text_size_for_content));
if (DEBUG) {
Log.d(TAG, "Medium view for mWidth: " + mWidth + " mHeight: " + mHeight
@@ -558,9 +558,6 @@ public class PeopleTileViewHelper {
}
views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
views.setTextViewText(R.id.text_content, statusText);
- if (mLayoutSize == LAYOUT_LARGE) {
- views.setInt(R.id.content, "setGravity", Gravity.BOTTOM);
- }
Icon statusIcon = status.getIcon();
if (statusIcon != null) {
@@ -570,6 +567,7 @@ public class PeopleTileViewHelper {
// Show 1-line subtext on large layout with status images.
if (mLayoutSize == LAYOUT_LARGE) {
if (DEBUG) Log.d(TAG, "Remove name for large");
+ views.setInt(R.id.content, "setGravity", Gravity.BOTTOM);
views.setViewVisibility(R.id.name, View.GONE);
views.setColorAttr(R.id.text_content, "setTextColor",
android.R.attr.textColorPrimary);
@@ -830,6 +828,8 @@ public class PeopleTileViewHelper {
views.setViewPadding(R.id.name, 0, 0, 0,
mContext.getResources().getDimensionPixelSize(
R.dimen.below_name_text_padding));
+ // All large layouts besides missed calls & statuses with images, have gravity top.
+ views.setInt(R.id.content, "setGravity", Gravity.TOP);
}
// For all layouts except Missed Calls, ensure predefined icon is regular sized.
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 39faf5a1eed9..775a3afb7bde 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -199,7 +199,8 @@ public class PeopleSpaceWidgetManager {
"Received updated conversation: "
+ conversation.getShortcutInfo().getLabel());
}
- updateWidgetsWithConversationChanged(conversation);
+ mBgExecutor.execute(() ->
+ updateWidgetsWithConversationChanged(conversation));
}
}
@@ -675,7 +676,7 @@ public class PeopleSpaceWidgetManager {
updatedTile.setUserIcon(icon);
}
if (DEBUG) Log.d(TAG, "Statuses: " + conversation.getStatuses().toString());
- NotificationChannel channel = conversation.getParentNotificationChannel();
+ NotificationChannel channel = conversation.getNotificationChannel();
if (channel != null) {
if (DEBUG) Log.d(TAG, "Important:" + channel.isImportantConversation());
updatedTile.setIsImportantConversation(channel.isImportantConversation());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
index f56a2bbefaf7..49d18e62346a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
@@ -20,9 +20,11 @@ import static com.android.systemui.qs.customize.QSCustomizer.EXTRA_QS_CUSTOMIZIN
import static com.android.systemui.qs.customize.QSCustomizer.MENU_RESET;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
+import android.widget.TextView;
import android.widget.Toolbar;
import android.widget.Toolbar.OnMenuItemClickListener;
@@ -139,6 +141,20 @@ public class QSCustomizerController extends ViewController<QSCustomizer> {
RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
// Do not read row and column every time it changes.
}
+
+ public void calculateItemDecorationsForChild(View child, Rect outRect) {
+ // There's only a single item decoration that cares about the itemOffsets, so
+ // we just call it manually so they are never cached. This way, it's updated as the
+ // tiles are moved around.
+ // It only sets the left and right margin and only cares about tiles (not TextView).
+ if (!(child instanceof TextView)) {
+ outRect.setEmpty();
+ mTileAdapter.getMarginItemDecoration().getItemOffsets(outRect, child,
+ recyclerView, new RecyclerView.State());
+ ((LayoutParams) child.getLayoutParams()).leftMargin = outRect.left;
+ ((LayoutParams) child.getLayoutParams()).rightMargin = outRect.right;
+ }
+ }
};
layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
recyclerView.setLayoutManager(layout);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index ba65d5163881..5a60d2624a43 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -690,9 +690,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
if (parent.getLayoutManager() == null) return;
GridLayoutManager lm = ((GridLayoutManager) parent.getLayoutManager());
- SpanSizeLookup span = lm.getSpanSizeLookup();
- ViewHolder holder = parent.getChildViewHolder(view);
- int column = span.getSpanIndex(holder.getBindingAdapterPosition(), lm.getSpanCount());
+ int column = ((GridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
if (view instanceof TextView) {
super.getItemOffsets(outRect, view, parent, state);
@@ -702,14 +700,30 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
// columns).
outRect.left = mHalfMargin;
outRect.right = mHalfMargin;
- } else if (column == 0) {
- // Leftmost column when not using side margins. Should only have margin on the
- // right.
- outRect.right = mHalfMargin;
} else {
- // Rightmost column when not using side margins. Should only have margin on the
- // left.
- outRect.left = mHalfMargin;
+ // Leftmost or rightmost column
+ if (parent.isLayoutRtl()) {
+ if (column == 0) {
+ // Rightmost column
+ outRect.left = mHalfMargin;
+ outRect.right = 0;
+ } else {
+ // Leftmost column
+ outRect.left = 0;
+ outRect.right = mHalfMargin;
+ }
+ } else {
+ // Non RTL
+ if (column == 0) {
+ // Leftmost column
+ outRect.left = 0;
+ outRect.right = mHalfMargin;
+ } else {
+ // Rightmost column
+ outRect.left = mHalfMargin;
+ outRect.right = 0;
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 30c9b44536e1..d5b4032b1c0f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -22,6 +22,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.HardwareRenderer;
+import android.graphics.Matrix;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
@@ -31,9 +32,12 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
import android.util.Log;
import android.view.ScrollCaptureResponse;
import android.view.View;
+import android.view.ViewTreeObserver;
import android.widget.ImageView;
import androidx.constraintlayout.widget.ConstraintLayout;
@@ -74,6 +78,7 @@ public class LongScreenshotActivity extends Activity {
private ImageView mPreview;
private ImageView mTransitionView;
+ private ImageView mEnterTransitionView;
private View mSave;
private View mEdit;
private View mShare;
@@ -111,7 +116,7 @@ public class LongScreenshotActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate(savedInstanceState = " + savedInstanceState + ")");
super.onCreate(savedInstanceState);
-
+ postponeEnterTransition();
setContentView(R.layout.long_screenshot);
mPreview = requireViewById(R.id.preview);
@@ -122,6 +127,7 @@ public class LongScreenshotActivity extends Activity {
mMagnifierView = requireViewById(R.id.magnifier);
mCropView.setCropInteractionListener(mMagnifierView);
mTransitionView = requireViewById(R.id.transition);
+ mEnterTransitionView = requireViewById(R.id.enter_transition);
mSave.setOnClickListener(this::onClicked);
mEdit.setOnClickListener(this::onClicked);
@@ -184,8 +190,8 @@ public class LongScreenshotActivity extends Activity {
private void onLongScreenshotReceived(LongScreenshot longScreenshot) {
Log.d(TAG, "onLongScreenshotReceived(longScreenshot=" + longScreenshot + ")");
mLongScreenshot = longScreenshot;
- mPreview.setImageDrawable(mLongScreenshot.getDrawable());
- updateImageDimensions();
+ Drawable drawable = mLongScreenshot.getDrawable();
+ mPreview.setImageDrawable(drawable);
mCropView.setVisibility(View.VISIBLE);
mMagnifierView.setDrawable(mLongScreenshot.getDrawable(),
mLongScreenshot.getWidth(), mLongScreenshot.getHeight());
@@ -196,9 +202,35 @@ public class LongScreenshotActivity extends Activity {
float bottomFraction = Math.min(1f,
1 - (mLongScreenshot.getBottom() - mLongScreenshot.getPageHeight())
/ (float) mLongScreenshot.getHeight());
- mCropView.animateBoundaryTo(CropView.CropBoundary.TOP, topFraction);
- mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, bottomFraction);
- setButtonsEnabled(true);
+
+ mEnterTransitionView.setImageDrawable(drawable);
+
+ mEnterTransitionView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ mEnterTransitionView.getViewTreeObserver().removeOnPreDrawListener(this);
+ updateImageDimensions();
+ startPostponedEnterTransition();
+ if (isActivityTransitionRunning()) {
+ getWindow().getSharedElementEnterTransition().addListener(
+ new TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ super.onTransitionEnd(transition);
+ mPreview.animate().alpha(1f);
+ mCropView.animateBoundaryTo(
+ CropView.CropBoundary.TOP, topFraction);
+ mCropView.animateBoundaryTo(
+ CropView.CropBoundary.BOTTOM, bottomFraction);
+ setButtonsEnabled(true);
+ mEnterTransitionView.setVisibility(View.GONE);
+ }
+ });
+ }
+ return true;
+ }
+ });
// Immediately export to temp image file for saved state
mCacheSaveFuture = mImageExporter.exportAsTempFile(mBackgroundExecutor,
@@ -412,22 +444,26 @@ public class LongScreenshotActivity extends Activity {
// The image width and height on screen
int imageHeight = previewHeight;
int imageWidth = previewWidth;
+ float scale;
+ int extraPadding = 0;
if (imageRatio > viewRatio) {
// Image is full width and height is constrained, compute extra padding to inform
// CropView
imageHeight = (int) (previewHeight * viewRatio / imageRatio);
- int extraPadding = (previewHeight - imageHeight) / 2;
+ extraPadding = (previewHeight - imageHeight) / 2;
mCropView.setExtraPadding(extraPadding + mPreview.getPaddingTop(),
extraPadding + mPreview.getPaddingBottom());
imageTop += (previewHeight - imageHeight) / 2;
mCropView.setExtraPadding(extraPadding, extraPadding);
mCropView.setImageWidth(previewWidth);
+ scale = previewWidth / (float) mPreview.getDrawable().getIntrinsicWidth();
} else {
imageWidth = (int) (previewWidth * imageRatio / viewRatio);
imageLeft += (previewWidth - imageWidth) / 2;
// Image is full height
mCropView.setExtraPadding(mPreview.getPaddingTop(), mPreview.getPaddingBottom());
mCropView.setImageWidth((int) (previewHeight * imageRatio));
+ scale = previewHeight / (float) mPreview.getDrawable().getIntrinsicHeight();
}
// Update transition view's position and scale.
@@ -439,5 +475,20 @@ public class LongScreenshotActivity extends Activity {
params.width = boundaries.width();
params.height = boundaries.height();
mTransitionView.setLayoutParams(params);
+
+ ConstraintLayout.LayoutParams enterTransitionParams =
+ (ConstraintLayout.LayoutParams) mEnterTransitionView.getLayoutParams();
+ float topFraction = Math.max(0,
+ -mLongScreenshot.getTop() / (float) mLongScreenshot.getHeight());
+ enterTransitionParams.width = (int) (scale * drawable.getIntrinsicWidth());
+ enterTransitionParams.height = (int) (scale * mLongScreenshot.getPageHeight());
+ mEnterTransitionView.setLayoutParams(enterTransitionParams);
+
+ Matrix matrix = new Matrix();
+ matrix.setScale(scale, scale);
+ matrix.postTranslate(0, -scale * drawable.getIntrinsicHeight() * topFraction);
+ mEnterTransitionView.setImageMatrix(matrix);
+ mEnterTransitionView.setTranslationY(
+ topFraction * previewHeight + mPreview.getPaddingTop() + extraPadding);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index eaa6659790fa..b1e589f274a4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -16,7 +16,6 @@
package com.android.systemui.screenshot;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
@@ -289,6 +288,7 @@ public class ScreenshotController {
mWindowLayoutParams.setTitle("ScreenshotAnimation");
mWindowLayoutParams.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ mWindowLayoutParams.setFitInsetsTypes(0);
// This is needed to let touches pass through outside the touchable areas
mWindowLayoutParams.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
@@ -402,11 +402,6 @@ public class ScreenshotController {
Log.d(TAG, "reloadAssets()");
}
- // respect the display cutout in landscape (since we'd otherwise overlap) but not portrait
- int orientation = mContext.getResources().getConfiguration().orientation;
- mWindowLayoutParams.setFitInsetsTypes(
- orientation == ORIENTATION_PORTRAIT ? 0 : WindowInsets.Type.displayCutout());
-
// Inflate the screenshot layout
mScreenshotView = (ScreenshotView)
LayoutInflater.from(mContext).inflate(R.layout.global_screenshot, null);
@@ -494,17 +489,6 @@ public class ScreenshotController {
saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, true);
}
- private void updateDisplayCutout() {
- // respect the display cutout in landscape (since we'd otherwise overlap) but not portrait
- int orientation = mContext.getResources().getConfiguration().orientation;
- mWindowLayoutParams.setFitInsetsTypes(
- orientation == ORIENTATION_PORTRAIT ? 0 : WindowInsets.Type.displayCutout());
- final View decorView = mWindow.peekDecorView();
- if (decorView != null && decorView.isAttachedToWindow()) {
- mWindowManager.updateViewLayout(decorView, mWindowLayoutParams);
- }
- }
-
private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
Insets screenInsets, boolean showFlash) {
if (mAccessibilityManager.isEnabled()) {
@@ -528,8 +512,8 @@ public class ScreenshotController {
mScreenshotView.reset();
}
- int orientation = mContext.getResources().getConfiguration().orientation;
- mScreenshotView.updateOrientation(orientation == ORIENTATION_PORTRAIT);
+ mScreenshotView.updateOrientation(mWindowManager.getCurrentWindowMetrics()
+ .getWindowInsets().getDisplayCutout());
mScreenBitmap = screenshot;
@@ -563,7 +547,9 @@ public class ScreenshotController {
// Delay scroll capture eval a bit to allow the underlying activity
// to set up in the new orientation.
mScreenshotHandler.postDelayed(this::requestScrollCapture, 150);
- updateDisplayCutout();
+ mScreenshotView.updateDisplayCutoutMargins(
+ mWindowManager.getCurrentWindowMetrics().getWindowInsets()
+ .getDisplayCutout());
}
});
});
@@ -612,7 +598,7 @@ public class ScreenshotController {
// No connection means that the target window wasn't found
// or that it cannot support scroll capture.
Log.d(TAG, "ScrollCapture: " + mLastScrollCaptureResponse.getDescription() + " ["
- + mLastScrollCaptureResponse.getWindowTitle() + "]");
+ + mLastScrollCaptureResponse.getWindowTitle() + "]");
return;
}
Log.d(TAG, "ScrollCapture: connected to window ["
@@ -620,6 +606,7 @@ public class ScreenshotController {
final ScrollCaptureResponse response = mLastScrollCaptureResponse;
mScreenshotView.showScrollChip(/* onClick */ () -> {
+ mScreenshotView.prepareScrollingTransition(response, mScreenBitmap);
// Clear the reference to prevent close() in dismissScreenshot
mLastScrollCaptureResponse = null;
final ListenableFuture<ScrollCaptureController.LongScreenshot> future =
@@ -637,9 +624,14 @@ public class ScreenshotController {
final Intent intent = new Intent(mContext, LongScreenshotActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mContext.startActivity(intent);
- dismissScreenshot(false);
+ Pair<ActivityOptions, ExitTransitionCoordinator> transition =
+ ActivityOptions.startSharedElementAnimation(
+ mWindow, new ScreenshotExitTransitionCallbacks(), null,
+ Pair.create(mScreenshotView.getScrollablePreview(),
+ ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME));
+ transition.second.startExit();
+ mContext.startActivity(intent, transition.first.toBundle());
}, mMainExecutor);
});
} catch (CancellationException e) {
@@ -663,7 +655,8 @@ public class ScreenshotController {
}
@Override
- public void onWindowDetached() { }
+ public void onWindowDetached() {
+ }
});
}
@@ -861,24 +854,9 @@ public class ScreenshotController {
*/
private Supplier<ActionTransition> getActionTransitionSupplier() {
return () -> {
- ExitTransitionCallbacks cb = new ExitTransitionCallbacks() {
- @Override
- public boolean isReturnTransitionAllowed() {
- return false;
- }
-
- @Override
- public void hideSharedElements() {
- finishDismiss();
- }
-
- @Override
- public void onFinish() {
- }
- };
-
Pair<ActivityOptions, ExitTransitionCoordinator> transition =
- ActivityOptions.startSharedElementAnimation(mWindow, cb, null,
+ ActivityOptions.startSharedElementAnimation(
+ mWindow, new ScreenshotExitTransitionCallbacks(), null,
Pair.create(mScreenshotView.getScreenshotPreview(),
ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME));
transition.second.startExit();
@@ -964,4 +942,20 @@ public class ScreenshotController {
}
return matchWithinTolerance;
}
+
+ private class ScreenshotExitTransitionCallbacks implements ExitTransitionCallbacks {
+ @Override
+ public boolean isReturnTransitionAllowed() {
+ return false;
+ }
+
+ @Override
+ public void hideSharedElements() {
+ finishDismiss();
+ }
+
+ @Override
+ public void onFinish() {
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 77e1d154f3ac..c33c2dbc16a0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -40,6 +40,7 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Insets;
+import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
@@ -54,9 +55,11 @@ import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
+import android.view.DisplayCutout;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.ScrollCaptureResponse;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
@@ -71,6 +74,8 @@ import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
@@ -125,9 +130,11 @@ public class ScreenshotView extends FrameLayout implements
private boolean mDirectionLTR;
private ScreenshotSelectorView mScreenshotSelectorView;
+ private ImageView mScrollingScrim;
private View mScreenshotStatic;
private ImageView mScreenshotPreview;
private View mScreenshotPreviewBorder;
+ private ImageView mScrollablePreview;
private ImageView mScreenshotFlash;
private ImageView mActionsContainerBackground;
private HorizontalScrollView mActionsContainer;
@@ -266,6 +273,7 @@ public class ScreenshotView extends FrameLayout implements
@Override // View
protected void onFinishInflate() {
+ mScrollingScrim = requireNonNull(findViewById(R.id.screenshot_scrolling_scrim));
mScreenshotStatic = requireNonNull(findViewById(R.id.global_screenshot_static));
mScreenshotPreview = requireNonNull(findViewById(R.id.global_screenshot_preview));
mScreenshotPreviewBorder = requireNonNull(
@@ -279,6 +287,7 @@ public class ScreenshotView extends FrameLayout implements
mBackgroundProtection = requireNonNull(
findViewById(R.id.global_screenshot_actions_background));
mDismissButton = requireNonNull(findViewById(R.id.global_screenshot_dismiss_button));
+ mScrollablePreview = requireNonNull(findViewById(R.id.screenshot_scrollable_preview));
mScreenshotFlash = requireNonNull(findViewById(R.id.global_screenshot_flash));
mScreenshotSelectorView = requireNonNull(findViewById(R.id.global_screenshot_selector));
mShareChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_share_chip));
@@ -327,6 +336,10 @@ public class ScreenshotView extends FrameLayout implements
return mScreenshotPreview;
}
+ View getScrollablePreview() {
+ return mScrollablePreview;
+ }
+
/**
* Set up the logger and callback on dismissal.
*
@@ -348,12 +361,35 @@ public class ScreenshotView extends FrameLayout implements
mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
}
- void updateOrientation(boolean portrait) {
- mOrientationPortrait = portrait;
+ void updateDisplayCutoutMargins(DisplayCutout cutout) {
+ int orientation = mContext.getResources().getConfiguration().orientation;
+ mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
+ FrameLayout.LayoutParams p =
+ (FrameLayout.LayoutParams) mScreenshotStatic.getLayoutParams();
+ if (cutout == null) {
+ p.setMargins(0, 0, 0, 0);
+ } else {
+ Insets waterfall = cutout.getWaterfallInsets();
+ if (mOrientationPortrait) {
+ p.setMargins(waterfall.left, Math.max(cutout.getSafeInsetTop(), waterfall.top),
+ waterfall.right, Math.max(cutout.getSafeInsetBottom(), waterfall.bottom));
+ } else {
+ p.setMargins(Math.max(cutout.getSafeInsetLeft(), waterfall.left), waterfall.top,
+ Math.max(cutout.getSafeInsetRight(), waterfall.right), waterfall.bottom);
+ }
+ }
+ mScreenshotStatic.setLayoutParams(p);
+ mScreenshotStatic.requestLayout();
+ }
+
+ void updateOrientation(DisplayCutout cutout) {
+ int orientation = mContext.getResources().getConfiguration().orientation;
+ mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
+ updateDisplayCutoutMargins(cutout);
int screenshotFixedSize =
mContext.getResources().getDimensionPixelSize(R.dimen.global_screenshot_x_scale);
ViewGroup.LayoutParams params = mScreenshotPreview.getLayoutParams();
- if (portrait) {
+ if (mOrientationPortrait) {
params.width = screenshotFixedSize;
params.height = LayoutParams.WRAP_CONTENT;
mScreenshotPreview.setScaleType(ImageView.ScaleType.FIT_START);
@@ -362,6 +398,7 @@ public class ScreenshotView extends FrameLayout implements
params.height = screenshotFixedSize;
mScreenshotPreview.setScaleType(ImageView.ScaleType.FIT_END);
}
+
mScreenshotPreview.setLayoutParams(params);
}
@@ -676,6 +713,38 @@ public class ScreenshotView extends FrameLayout implements
}
}
+ private Rect scrollableAreaOnScreen(ScrollCaptureResponse response) {
+ Rect r = new Rect(response.getBoundsInWindow());
+ Rect windowInScreen = response.getWindowBounds();
+ r.offset(windowInScreen.left, windowInScreen.top);
+ r.intersect(new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
+ return r;
+ }
+
+ void prepareScrollingTransition(ScrollCaptureResponse response, Bitmap screenBitmap) {
+ Rect scrollableArea = scrollableAreaOnScreen(response);
+ float scale = mCornerSizeX
+ / (mOrientationPortrait ? screenBitmap.getWidth() : screenBitmap.getHeight());
+ ConstraintLayout.LayoutParams params =
+ (ConstraintLayout.LayoutParams) mScrollablePreview.getLayoutParams();
+
+ params.width = (int) (scale * scrollableArea.width());
+ params.height = (int) (scale * scrollableArea.height());
+ Matrix matrix = new Matrix();
+ matrix.setScale(scale, scale);
+ matrix.postTranslate(0, -scrollableArea.top * scale);
+
+ mScrollablePreview.setTranslationX(scale * scrollableArea.left);
+ mScrollablePreview.setTranslationY(scale * scrollableArea.top);
+ mScrollablePreview.setImageMatrix(matrix);
+
+ mScrollingScrim.setImageBitmap(screenBitmap);
+ mScrollingScrim.setVisibility(View.VISIBLE);
+ mScrollablePreview.setImageBitmap(screenBitmap);
+ mScrollablePreview.setVisibility(View.VISIBLE);
+ createScreenshotFadeDismissAnimation(true).start();
+ }
+
boolean isDismissing() {
return (mDismissAnimation != null && mDismissAnimation.isRunning());
}
@@ -776,7 +845,7 @@ public class ScreenshotView extends FrameLayout implements
transition.action.actionIntent.send();
// fade out non-preview UI
- createScreenshotFadeDismissAnimation().start();
+ createScreenshotFadeDismissAnimation(false).start();
} catch (PendingIntent.CanceledException e) {
mPendingSharedTransition = false;
if (transition.onCancelRunnable != null) {
@@ -814,7 +883,7 @@ public class ScreenshotView extends FrameLayout implements
return animSet;
}
- private ValueAnimator createScreenshotFadeDismissAnimation() {
+ ValueAnimator createScreenshotFadeDismissAnimation(boolean fadePreview) {
ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
alphaAnim.addUpdateListener(animation -> {
float alpha = 1 - animation.getAnimatedFraction();
@@ -822,6 +891,10 @@ public class ScreenshotView extends FrameLayout implements
mActionsContainerBackground.setAlpha(alpha);
mActionsContainer.setAlpha(alpha);
mBackgroundProtection.setAlpha(alpha);
+ mScreenshotPreviewBorder.setAlpha(alpha);
+ if (fadePreview) {
+ mScreenshotPreview.setAlpha(alpha);
+ }
});
alphaAnim.setDuration(600);
return alphaAnim;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index 2863074bee0a..94e314948779 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -405,6 +405,10 @@ public class ScrollCaptureClient {
return new Rect(mWindowBounds);
}
+ public Rect getBoundsInWindow() {
+ return new Rect(mBoundsInWindow);
+ }
+
@Override
public int getMaxTiles() {
return mMaxTiles;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 84728f699e91..760bee21b0d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -98,8 +98,6 @@ class NotificationWakeUpCoordinator @Inject constructor(
}
}
- private var animatingScreenOff = false
-
private var collapsedEnoughToHide: Boolean = false
var pulsing: Boolean = false
@@ -236,11 +234,11 @@ class NotificationWakeUpCoordinator @Inject constructor(
}
override fun onDozeAmountChanged(linear: Float, eased: Float) {
- if (overrideDozeAmountIfBypass()) {
+ if (overrideDozeAmountIfAnimatingScreenOff(linear)) {
return
}
- if (overrideDozeAmountIfAnimatingScreenOff(linear)) {
+ if (overrideDozeAmountIfBypass()) {
return
}
@@ -267,7 +265,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
override fun onStateChanged(newState: Int) {
if (unlockedScreenOffAnimationController.shouldPlayScreenOffAnimation()) {
- if (animatingScreenOff &&
+ if (unlockedScreenOffAnimationController.isScreenOffAnimationPlaying() &&
state == StatusBarState.KEYGUARD &&
newState == StatusBarState.SHADE) {
// If we're animating the screen off and going from KEYGUARD back to SHADE, the
@@ -275,12 +273,16 @@ class NotificationWakeUpCoordinator @Inject constructor(
// dozing) so that the notifications are no longer hidden.
setDozeAmount(0f, 0f)
}
+ }
+
+ if (overrideDozeAmountIfAnimatingScreenOff(mLinearDozeAmount)) {
+ return
+ }
- animatingScreenOff =
- state == StatusBarState.SHADE && newState == StatusBarState.KEYGUARD
+ if (overrideDozeAmountIfBypass()) {
+ return
}
- overrideDozeAmountIfBypass()
if (bypassController.bypassEnabled &&
newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED &&
(!statusBarStateController.isDozing || shouldAnimateVisibility())) {
@@ -330,12 +332,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
* animation. If true, the original doze amount should be ignored.
*/
private fun overrideDozeAmountIfAnimatingScreenOff(linearDozeAmount: Float): Boolean {
- if (animatingScreenOff) {
- if (linearDozeAmount == 1f) {
- animatingScreenOff = false
- return false
- }
-
+ if (unlockedScreenOffAnimationController.isScreenOffAnimationPlaying()) {
setDozeAmount(1f, 1f)
return true
}
@@ -395,11 +392,6 @@ class NotificationWakeUpCoordinator @Inject constructor(
override fun onDozingChanged(isDozing: Boolean) {
if (isDozing) {
setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
- } else {
- // We only unset the flag once we fully went asleep. If the user interrupts the
- // animation in the middle, we have to abort the animation as well to make sure
- // the notifications are visible again.
- animatingScreenOff = false
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 3190927dc24a..763d197847c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -488,7 +488,8 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
@Override
public void setLayerType(int layerType, Paint paint) {
- if (hasOverlappingRendering()) {
+ // Allow resetting the layerType to NONE regardless of overlappingRendering
+ if (layerType == LAYER_TYPE_NONE || hasOverlappingRendering()) {
super.setLayerType(layerType, paint);
}
}
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 2c2a17001326..8277fae64a62 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
@@ -106,6 +106,7 @@ import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
import com.android.systemui.util.Assert;
@@ -456,6 +457,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private long mNumHeadsUp;
private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
private final FeatureFlags mFeatureFlags;
+ private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private boolean mShouldUseSplitNotificationShade;
private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
@@ -497,11 +499,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
GroupMembershipManager groupMembershipManager,
GroupExpansionManager groupExpansionManager,
AmbientState ambientState,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
super(context, attrs, 0, 0);
Resources res = getResources();
mSectionsManager = notificationSectionsManager;
mFeatureFlags = featureFlags;
+ mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
mShouldUseSplitNotificationShade = shouldUseSplitNotificationShade(mFeatureFlags, res);
mSectionsManager.initialize(this, LayoutInflater.from(context));
mSections = mSectionsManager.createSectionsForBuckets();
@@ -606,6 +610,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
RemoteInputController remoteInputController = mRemoteInputManager.getController();
boolean showFooterView = (showDismissView || mController.hasActiveNotifications())
&& mStatusBarState != StatusBarState.KEYGUARD
+ && !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
&& (remoteInputController == null || !remoteInputController.isRemoteInputActive());
boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
@@ -4617,7 +4622,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@VisibleForTesting
- protected void setStatusBarState(int statusBarState) {
+ public void setStatusBarState(int statusBarState) {
mStatusBarState = statusBarState;
mAmbientState.setStatusBarState(statusBarState);
updateSpeedBumpIndex();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index c911e3d111cf..da37aa5ac943 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -83,9 +83,13 @@ public class KeyguardBouncer {
private final Runnable mRemoveViewRunnable = this::removeView;
private final KeyguardBypassController mKeyguardBypassController;
private KeyguardHostViewController mKeyguardViewController;
+ private final List<KeyguardResetCallback> mResetCallbacks = new ArrayList<>();
private final Runnable mResetRunnable = ()-> {
if (mKeyguardViewController != null) {
mKeyguardViewController.resetSecurityContainer();
+ for (KeyguardResetCallback callback : mResetCallbacks) {
+ callback.onKeyguardReset();
+ }
}
};
@@ -573,6 +577,14 @@ public class KeyguardBouncer {
}
}
+ public void addKeyguardResetCallback(KeyguardResetCallback callback) {
+ mResetCallbacks.add(callback);
+ }
+
+ public void removeKeyguardResetCallback(KeyguardResetCallback callback) {
+ mResetCallbacks.remove(callback);
+ }
+
public interface BouncerExpansionCallback {
void onFullyShown();
void onStartingToHide();
@@ -593,6 +605,10 @@ public class KeyguardBouncer {
default void onVisibilityChanged(boolean isVisible) {}
}
+ public interface KeyguardResetCallback {
+ void onKeyguardReset();
+ }
+
/** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
public static class Factory {
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 7c2723d724ce..29bf1edfabc4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -24,7 +24,6 @@ import android.content.res.Resources;
import android.util.MathUtils;
import com.android.keyguard.KeyguardStatusView;
-import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView;
@@ -153,8 +152,6 @@ public class KeyguardClockPositionAlgorithm {
*/
private int mUnlockedStackScrollerPadding;
- private int mLockScreenMode;
-
private boolean mIsSplitShade;
/**
@@ -228,13 +225,6 @@ public class KeyguardClockPositionAlgorithm {
}
}
- /**
- * Update lock screen mode for testing different layouts
- */
- public void onLockScreenModeChanged(int mode) {
- mLockScreenMode = mode;
- }
-
public float getMinStackScrollerPadding() {
return mBypassEnabled ? mUnlockedStackScrollerPadding
: mMinTopMargin + mKeyguardStatusHeight + mClockNotificationsMargin;
@@ -245,11 +235,7 @@ public class KeyguardClockPositionAlgorithm {
}
private int getExpandedPreferredClockY() {
- if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
- return mMinTopMargin + mUserSwitchHeight;
- }
- return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? mClockPreferredY
- : getExpandedClockPosition();
+ return mMinTopMargin + mUserSwitchHeight;
}
/**
@@ -278,29 +264,20 @@ public class KeyguardClockPositionAlgorithm {
}
private int getClockY(float panelExpansion, float darkAmount) {
- // Dark: Align the bottom edge of the clock at about half of the screen:
- float clockYDark = (mHasCustomClock ? mClockPreferredY : getMaxClockY())
- + burnInPreventionOffsetY();
- clockYDark = MathUtils.max(0, clockYDark);
-
float clockYRegular = getExpandedPreferredClockY();
float clockYBouncer = -mKeyguardStatusHeight;
// Move clock up while collapsing the shade
float shadeExpansion = Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(panelExpansion);
float clockY = MathUtils.lerp(clockYBouncer, clockYRegular, shadeExpansion);
- clockYDark = MathUtils.lerp(clockYBouncer, clockYDark, shadeExpansion);
-
- darkAmount = mBypassEnabled && !mHasCustomClock ? 1.0f : darkAmount;
- if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
- // This will keep the clock at the top but out of the cutout area
- float shift = 0;
- if (clockY - mBurnInPreventionOffsetYLargeClock < mCutoutTopInset) {
- shift = mCutoutTopInset - (clockY - mBurnInPreventionOffsetYLargeClock);
- }
- clockYDark = clockY + burnInPreventionOffsetY() + shift;
+ // This will keep the clock at the top but out of the cutout area
+ float shift = 0;
+ if (clockY - mBurnInPreventionOffsetYLargeClock < mCutoutTopInset) {
+ shift = mCutoutTopInset - (clockY - mBurnInPreventionOffsetYLargeClock);
}
+ float clockYDark = clockY + burnInPreventionOffsetY() + shift;
+
return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mOverStretchAmount);
}
@@ -333,19 +310,12 @@ public class KeyguardClockPositionAlgorithm {
}
private float burnInPreventionOffsetY() {
- int offset = mBurnInPreventionOffsetY;
- if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
- offset = mBurnInPreventionOffsetYLargeClock;
- }
+ int offset = mBurnInPreventionOffsetYLargeClock;
return getBurnInOffset(offset * 2, false /* xAxis */) - offset;
}
private float burnInPreventionOffsetX() {
- if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
- return getBurnInOffset(mBurnInPreventionOffsetX * 2, true /* xAxis */)
- - mBurnInPreventionOffsetX;
- }
return getBurnInOffset(mBurnInPreventionOffsetX, true /* xAxis */);
}
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 e2d64b09aee9..604033efc944 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -254,12 +254,6 @@ public class NotificationPanelViewController extends PanelViewController {
new KeyguardUpdateMonitorCallback() {
@Override
- public void onLockScreenModeChanged(int mode) {
- mLockScreenMode = mode;
- mClockPositionAlgorithm.onLockScreenModeChanged(mode);
- }
-
- @Override
public void onBiometricAuthenticated(int userId,
BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {
@@ -594,7 +588,6 @@ public class NotificationPanelViewController extends PanelViewController {
private final Executor mUiExecutor;
private final SecureSettings mSecureSettings;
- private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
private KeyguardMediaController mKeyguardMediaController;
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
@@ -1254,10 +1247,7 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
expandedFraction,
totalHeight,
- mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1
- ? mKeyguardStatusViewController.getHeight()
- : (int) (mKeyguardStatusViewController.getHeight()
- - mShelfHeight / 2.0f - mDarkIconSize / 2.0f),
+ mKeyguardStatusViewController.getHeight(),
userIconHeight,
clockPreferredY, userSwitcherPreferredY, hasCustomClock(),
hasVisibleNotifications, darkamount, mOverStretchAmount,
@@ -2535,7 +2525,9 @@ public class NotificationPanelViewController extends PanelViewController {
break;
case FLING_HIDE:
default:
- mQs.closeDetail();
+ if (mQs != null) {
+ mQs.closeDetail();
+ }
target = 0;
}
if (target == mQsExpansionHeight) {
@@ -4283,7 +4275,8 @@ public class NotificationPanelViewController extends PanelViewController {
/**
* Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the
* screen off animation controller in order to animate in AOD without "actually" fully switching
- * to the KEYGUARD state.
+ * to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the
+ * change.
*/
public void showAodUi() {
setDozing(true /* dozing */, false /* animate */, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 09779d12f7b3..ce61577903c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4460,7 +4460,6 @@ public class StatusBar extends SystemUI implements DemoMode,
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
}
- updateLightRevealScrimVisibility();
Trace.endSection();
}
@@ -4895,11 +4894,6 @@ public class StatusBar extends SystemUI implements DemoMode,
return;
}
- if (mDozeServiceHost.isPulsing()) {
- mLightRevealScrim.setVisibility(View.GONE);
- return;
- }
-
if (mFeatureFlags.useNewLockscreenAnimations()
&& (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
mLightRevealScrim.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index b9b62b415c00..753def0b0f1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -86,7 +86,9 @@ public class WifiSignalController extends
@Override
public void notifyListeners(SignalCallback callback) {
if (mCurrentState.isCarrierMerged) {
- notifyListenersForCarrierWifi(callback);
+ if (mCurrentState.isDefault) {
+ notifyListenersForCarrierWifi(callback);
+ }
} else {
notifyListenersForNonCarrierWifi(callback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 428921ee34ec..ca1f55e95ff4 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -240,11 +240,14 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_STARTED.equals(intent.getAction())
- || Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction())) {
- if (!mDeviceProvisionedController.isCurrentUserSetup()) {
+ boolean newWorkProfile = Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction());
+ boolean userStarted = Intent.ACTION_USER_STARTED.equals(intent.getAction());
+ boolean isManagedProfile = mUserManager.isManagedProfile(
+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+ if (userStarted || newWorkProfile) {
+ if (!mDeviceProvisionedController.isCurrentUserSetup() && isManagedProfile) {
Log.i(TAG, "User setup not finished when " + intent.getAction()
- + " was received. Deferring...");
+ + " was received. Deferring... Managed profile? " + isManagedProfile);
return;
}
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
@@ -326,17 +329,22 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
Runnable updateColors = () -> {
WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
getLatestWallpaperType());
- mMainExecutor.execute(() -> {
+ Runnable applyColors = () -> {
if (DEBUG) Log.d(TAG, "Boot colors: " + systemColor);
mCurrentColors = systemColor;
reevaluateSystemTheme(false /* forceReload */);
- });
+ };
+ if (mDeviceProvisionedController.isCurrentUserSetup()) {
+ mMainExecutor.execute(applyColors);
+ } else {
+ applyColors.run();
+ }
};
// Whenever we're going directly to setup wizard, we need to process colors synchronously,
// otherwise we'll see some jank when the activity is recreated.
if (!mDeviceProvisionedController.isCurrentUserSetup()) {
- mMainExecutor.execute(updateColors);
+ updateColors.run();
} else {
mBgExecutor.execute(updateColors);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 961822a598e7..228b9c3da319 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -932,6 +932,13 @@ public class VolumeDialogImpl implements VolumeDialog,
.start();
}
+ // When the ringer drawer is open, tapping the currently selected ringer will set the ringer
+ // to the current ringer mode. Change the content description to that, instead of the 'tap
+ // to change ringer mode' default.
+ mSelectedRingerContainer.setContentDescription(
+ mContext.getString(getStringDescriptionResourceForRingerMode(
+ mState.ringerModeInternal)));
+
mIsRingerDrawerOpen = true;
}
@@ -976,6 +983,11 @@ public class VolumeDialogImpl implements VolumeDialog,
.translationY(0f)
.start();
+ // When the drawer is closed, tapping the selected ringer drawer will open it, allowing the
+ // user to change the ringer.
+ mSelectedRingerContainer.setContentDescription(
+ mContext.getString(R.string.volume_ringer_change));
+
mIsRingerDrawerOpen = false;
}
@@ -1464,20 +1476,8 @@ public class VolumeDialogImpl implements VolumeDialog,
}
private void addAccessibilityDescription(View view, int currState, String hintLabel) {
- int currStateResId;
- switch (currState) {
- case RINGER_MODE_SILENT:
- currStateResId = R.string.volume_ringer_status_silent;
- break;
- case RINGER_MODE_VIBRATE:
- currStateResId = R.string.volume_ringer_status_vibrate;
- break;
- case RINGER_MODE_NORMAL:
- default:
- currStateResId = R.string.volume_ringer_status_normal;
- }
-
- view.setContentDescription(mContext.getString(currStateResId));
+ view.setContentDescription(
+ mContext.getString(getStringDescriptionResourceForRingerMode(currState)));
view.setAccessibilityDelegate(new AccessibilityDelegate() {
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
@@ -1487,6 +1487,18 @@ public class VolumeDialogImpl implements VolumeDialog,
});
}
+ private int getStringDescriptionResourceForRingerMode(int mode) {
+ switch (mode) {
+ case RINGER_MODE_SILENT:
+ return R.string.volume_ringer_status_silent;
+ case RINGER_MODE_VIBRATE:
+ return R.string.volume_ringer_status_vibrate;
+ case RINGER_MODE_NORMAL:
+ default:
+ return R.string.volume_ringer_status_normal;
+ }
+ }
+
/**
* Toggles enable state of views in a VolumeRow (not including seekbar or icon)
* Hides/shows zen icon
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 8758e1609fa8..43f7284e477e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -65,6 +65,7 @@ import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import org.junit.Assert;
import org.junit.Before;
@@ -105,6 +106,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationSwipeHelper mNotificationSwipeHelper;
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
@Mock private FeatureFlags mFeatureFlags;
+ @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Before
@UiThreadTest
@@ -143,7 +145,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mGroupMembershipManger,
mGroupExpansionManager,
mAmbientState,
- mFeatureFlags);
+ mFeatureFlags,
+ mUnlockedScreenOffAnimationController);
mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider,
mNotificationSwipeHelper);
mStackScroller = spy(mStackScrollerInternal);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 3cf92126c5c6..208790b24d8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -429,8 +429,19 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
}
@Test
+ public void onUserAdded_appliesTheme_ifNotManagedProfile() {
+ reset(mDeviceProvisionedController);
+ when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
+ mBroadcastReceiver.getValue().onReceive(null,
+ new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
public void onProfileAdded_ignoresUntilSetupComplete() {
reset(mDeviceProvisionedController);
+ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true);
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
verify(mThemeOverlayApplier, never())
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-af/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-af/strings.xml
index 8c47bcc9cb26..adc308600ebb 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-af/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-af/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Versteek (vermy programme in uitsnede-area)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Lewer programme onder uitsnede-area"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-am/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-am/strings.xml
index 0f1edf682d0a..648e1d4cf383 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-am/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-am/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"ደብቅ (በተቆራረጠ ክልል ውስጥ መተግበሪያዎችን ያስወግዱ)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ከተቆረጠው አከባቢ በታች የመተግበሪያዎች ምስልን ስራ"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ar/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ar/strings.xml
index 71f4f7cab57a..2d3b506d8cad 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ar/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ar/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"إخفاء (تجنّب التطبيقات في المناطق المقطوعة)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"عرض التطبيقات أسفل منطقة الصورة المقطوعة للشاشة"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-as/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-as/strings.xml
index e462ec68ddd9..db2b15a142c3 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-as/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-as/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"লুকুৱাওক (কাটআউট অংশৰ এপ্ বাদ দিয়ক)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"এপ্‌সমূহ কাটআউট অঞ্চলৰ তলত দেখুৱাওক"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-az/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-az/strings.xml
index fc7e546d8ede..a6b7c4346e7e 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-az/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-az/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Gizlədin (displey kəsiyində tətbiqlər görünməsin)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Tətbiqləri kəsilmə sahəsinin aşağısında göstərin"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-b+sr+Latn/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-b+sr+Latn/strings.xml
index c21fcda7e112..f80fa8d14054 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-b+sr+Latn/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-b+sr+Latn/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Sakrij (izbegavaj aplikacije u izrezanoj oblasti)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Prikazuj aplikacije ispod oblasti izreza"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-be/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-be/strings.xml
index 8ef67a22cd45..0e5c8bcb55a2 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-be/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-be/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Схаваць (не паказваць праграмы ў месце выраза)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Візуалізацыя праграм ніжэй месца выраза"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bg/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bg/strings.xml
index 8b81d6ad9fe7..e97bb57068ca 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bg/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bg/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Скриване (избягване на приложенията в областта на прореза на екрана)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Изобразяване на приложенията под областта на прореза"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml
deleted file mode 100644
index 15b1fdc2b6fb..000000000000
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"লুকান (কাটআউট অঞ্চলে অ্যাপটি দেখাবেন না)"</string>
-</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bs/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bs/strings.xml
index eb2b8d258bc6..9c9f43779b66 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bs/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bs/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Sakrij (izbjegavaj aplikacije u izrezanoj oblasti)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderovanje aplikacija ispod izrezanog područja"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ca/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ca/strings.xml
index be3e093d42f9..e0a577e5290f 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ca/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ca/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Amaga (evita les aplicacions de la regió de retall)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderitza les aplicacions per sota de l\'àrea de retallada"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-cs/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-cs/strings.xml
index 67ed6aff8661..0f64473c7260 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-cs/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-cs/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Skrýt (nezobrazovat aplikace v oblasti výřezu)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Vykreslovat aplikace pod oblastí výseče"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-da/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-da/strings.xml
index dcf70bf22125..d0cc43e8025f 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-da/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-da/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Skjul (undgå apps i cutout-område)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Gengiv apps under skærmhakkets område"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-de/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-de/strings.xml
index 86e373263776..a7759ea6175a 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-de/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-de/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ausblenden (Apps im Bereich der Display-Aussparung vermeiden)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Apps unterhalb des Aussparungs-Bereichs darstellen"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-el/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-el/strings.xml
index 9806966ffec7..b71679a1912f 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-el/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-el/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Απόκρυψη (αποφυγή εφαρμογών στην περιοχή εγκοπής)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Απόδοση εφαρμογών κάτω από την περιοχή εγκοπής"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rAU/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rAU/strings.xml
index a7700b9abd34..8c85cbdebb92 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rAU/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rAU/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Hide (avoid apps in cutout region)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render apps below cutout area"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rCA/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rCA/strings.xml
index a7700b9abd34..8c85cbdebb92 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rCA/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rCA/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Hide (avoid apps in cutout region)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render apps below cutout area"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rGB/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rGB/strings.xml
index a7700b9abd34..8c85cbdebb92 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rGB/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rGB/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Hide (avoid apps in cutout region)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render apps below cutout area"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rIN/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rIN/strings.xml
index a7700b9abd34..8c85cbdebb92 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rIN/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rIN/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Hide (avoid apps in cutout region)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render apps below cutout area"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rXC/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rXC/strings.xml
index e9b76fb8eb02..8b72d9f77c49 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rXC/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rXC/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‎‏‎Hide (avoid apps in cutout region)‎‏‎‎‏‎"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‏‎Render apps below cutout area‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es-rUS/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es-rUS/strings.xml
index ee5f8eabb343..359cdd0eab52 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es-rUS/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es-rUS/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ocultar (evitar apps en la región excluida)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar apps debajo del área de recorte"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es/strings.xml
index c244e49f3160..47f525ec1d28 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ocultar (evitar aplicaciones en la zona recortada)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar aplicaciones por debajo de la zona de recorte"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-et/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-et/strings.xml
index cf84a24a46db..0cc5a25868c2 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-et/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-et/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Peida (rakendusi ei kuvata ekraani väljalõikealal)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Väljalõikeala all olevate rakenduste renderdamine"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-eu/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-eu/strings.xml
index f1a6fda82f97..15d7d6045361 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-eu/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-eu/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ezkutatu (saihestu aplikazioak agertzea pantailaren mozketa-eremuan)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Errendatu mozketa-eremutik kanpo geratzen diren aplikazioak"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fa/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fa/strings.xml
index f31fad1f83ab..0865f7559ef9 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fa/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fa/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"پنهان کردن (از برنامه‌های موجود در منطقه بریده‌شده اجتناب می‌شود)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"پرداز زدن برنامه‌ها در زیر ناحیه بریده‌شده"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fi/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fi/strings.xml
index 5e626eea210c..1a6bf7a16839 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fi/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fi/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Piilota (vältä lovialueella olevia sovelluksia)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderöi sovellukset lovialueen alle"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml
index 5c9194e8e694..ea0a27b069da 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Masquer (éviter les applications dans la forme découpée)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Rendre les applications sous la zone de découpe"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr/strings.xml
index 321ee66d7257..6d91a9d603f4 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Masquer (éviter les applis dans la zone de l\'encoche)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Afficher les applis sous la zone d\'encoche"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gl/strings.xml
index a05a5fdc08d1..382497b1caf0 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gl/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ocultar (non mostrar as aplicacións que aparezan na zona recortada)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar aplicacións que aparezan na zona recortada"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml
deleted file mode 100644
index 557c7912166b..000000000000
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"છુપાવો (કટ આઉટ પ્રદેશમાં ઍપ બાકાત રાખો)"</string>
-</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hi/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hi/strings.xml
index c4ab1fe99bdc..e1f09f249bda 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hi/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hi/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"छिपाएं (कटआउट वाले हिस्से में ऐप्लिकेशन न दिखाएं)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ऐप्लिकेशन को कटआउट एरिया के नीचे दिखाएं"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hr/strings.xml
index a2c1feb26c25..db734e8254e5 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hr/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hr/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Sakrij (izbjegavaj aplikacije u području ureza)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderiraj aplikacije ispod područja ureza"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hu/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hu/strings.xml
index e8db0d1565de..264095b6f4e2 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hu/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hu/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Elrejtés (a képernyőkivágás területén szereplő alkalmazások elkerülése)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Alkalmazások megjelenítése a kivágási terület alatt"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hy/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hy/strings.xml
index 5b1838deb439..72e67ec1c424 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hy/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hy/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Թաքցնել (չցուցադրել հավելվածները էկրանի կտրված հատվածում)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Արտապատկերել հավելվածները էկրանի կտրված հատվածի ներքևում"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-in/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-in/strings.xml
index d40d73b72454..c49bf0ca939a 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-in/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-in/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Sembunyikan (hindari aplikasi di wilayah cutout)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render aplikasi di bawah area potongan"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-is/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-is/strings.xml
index 1a2466532dfe..0b90991b0b1e 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-is/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-is/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Fela (forðast forrit á útklipptu svæði)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Birta forrit fyrir neðan útklippta svæðið"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-it/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-it/strings.xml
index 90b98100de50..2a0f026b39a6 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-it/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-it/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Nascondi (evita le app nell\'area di ritaglio)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Visualizza le app sotto l\'area di ritaglio"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-iw/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-iw/strings.xml
index 0c4af2d69e4a..cc7a0a486c54 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-iw/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-iw/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"הסתרה (ללא אפליקציות באזור חיתוך התצוגה)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"עיבוד האפליקציות שמתחת לאזור המגרעת"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ja/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ja/strings.xml
index 69b9f24d1d08..9e99482e5e2a 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ja/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ja/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"非表示(カットアウト領域にアプリを表示しない)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"カットアウト領域の下でアプリをレンダリング"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ka/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ka/strings.xml
index 1ee2faef0bc6..5464a5699449 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ka/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ka/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"დამალვა (აპების არდაშვება ჭრილის უბანში)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"აპების ასახვა ჭრილის ქვემოთ"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kk/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kk/strings.xml
index 922152477d65..6a2623f8696f 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kk/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kk/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Жасыру (қолданбалар экран қиығында көрсетілмесін)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Экран ойығының астындағы қолданбаларды көрсету"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-km/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-km/strings.xml
index ea0a9d0dbc5b..4b4d169cc738 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-km/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-km/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"លាក់ (ជៀសវាងបង្ហាញកម្មវិធីនៅផ្នែកឆក)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"បំប្លែងកម្មវិធីខាងក្រោមផ្នែកឆក"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kn/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kn/strings.xml
deleted file mode 100644
index 10176a8d7b72..000000000000
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kn/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"ಮರೆಮಾಡಿ (ಕಟ್‌ಔಟ್ ಪ್ರದೇಶದಲ್ಲಿ ಆ್ಯಪ್‌ಗಳನ್ನು ತೋರಿಸದಂತೆ ತಡೆಯಿರಿ)"</string>
-</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ko/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ko/strings.xml
index 97856d35618c..4b9e64020eee 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ko/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ko/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"숨기기(컷아웃 영역에 앱을 표시하지 않음)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"컷아웃 영역 아래에 앱 렌더링"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ky/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ky/strings.xml
index 039bdf0b8888..1ac6a8bb9c1f 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ky/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ky/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Жашыруу (кесилген аймакта колдонмолор көрсөтүлбөсүн)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Колдонмолорду кесилген аймактын ылдый жагында көрсөтүү"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lo/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lo/strings.xml
index 29ec22453e93..4c38580169af 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lo/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lo/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"ເຊື່ອງ (ຫຼີກເວັ້ນແອັບໃນພື້ນທີ່ຕັດອອກ)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ສະແດງພາບແອັບຢູ່ທາງລຸ່ມພື້ນທີ່ຮອຍເສັ້ນ"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lt/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lt/strings.xml
index 09d86412e408..c43736d006dd 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lt/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lt/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Slėpti (nerodyti programų ekrano išpjovos srityje)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Pateikti programas po išpjovos sritimi"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lv/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lv/strings.xml
index f2367c648ed0..f95abb69abf5 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lv/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lv/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Paslēpt (nerādīt lietotnes ekrāna izgriezumā)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Atveidot lietotnes zem izgriezuma apgabala"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mk/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mk/strings.xml
index 67b45d3020a3..ff236be46b14 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mk/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mk/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Сокриј (избегнувај апликации во отсечен регион)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Прикажувај апликации под отсечената област"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ml/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ml/strings.xml
index 6e88f296e0ba..ef728ab64ab5 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ml/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ml/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"മറയ്‌ക്കുക (കട്ടൗട്ട് ഭാഗത്ത് ആപ്പുകൾ കാണിക്കരുത്)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"കട്ടൗട്ട് ഭാഗത്തിന് താഴെ ആപ്പുകൾ റെൻഡർ ചെയ്യുക"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mn/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mn/strings.xml
index 9bda419a1e17..23dbe0c822f0 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mn/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mn/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Нуух (тусгаарласан бүс дэх аппуудаас зайлсхийнэ)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Аппуудыг тасалж авсан хэсгийн доор буулгах"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml
deleted file mode 100644
index ecd0c0b4f25e..000000000000
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"लपवा (कटआउट भागामध्ये ॲप्स दाखवू नका)"</string>
-</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ms/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ms/strings.xml
index 5864ff8689dd..e348630e0447 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ms/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ms/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Sembunyikan (elakkan apl dalam kawasan potongan)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Serahkan apl di bawah kawasan potongan"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-my/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-my/strings.xml
index 0f3c0aaff18d..90cb0a5f56a4 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-my/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-my/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"ဝှက်ရန် (ဖြတ်ထုတ်ထားသောအပိုင်းရှိ အက်ပ်များကို မပြပါနှင့်)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ဖြတ်ထုတ်ထားသော နေရာအောက်ရှိ အက်ပ်များ ပြသရန်"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nb/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nb/strings.xml
index 8a1da687e573..b8b4e7526ab2 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nb/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nb/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Skjul (unngå apper i utklippsregionen)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Gjengi apper under utklippsområdet"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml
deleted file mode 100644
index 98d75129f64a..000000000000
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"लुकाइयोस् (कटआउट क्षेत्रमा एपहरू नदेखाइयोस्)"</string>
-</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nl/strings.xml
index 0e515147c0ab..68f5c0701beb 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nl/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Verbergen (apps in cutout-regio vermijden)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Apps renderen onder display-cutout"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-or/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-or/strings.xml
index b0552b87d5b3..162a29e8968c 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-or/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-or/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"ଲୁଚାନ୍ତୁ (କଟଆଉଟ୍ ରିଜନରେ ଆପଗୁଡ଼ିକୁ ଏଡ଼ାନ୍ତୁ)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ଆପଗୁଡ଼ିକୁ କଟଆଉଟ୍ ଏରିଆ ନିମ୍ନରେ ରେଣ୍ଡର୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pa/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pa/strings.xml
deleted file mode 100644
index 803a69d40213..000000000000
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pa/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"ਲੁਕਾਓ (ਕੱਟਆਊਟ ਖੇਤਰ ਵਿਚਲੀਆਂ ਐਪਾਂ ਨੂੰ ਨਾ ਛੇੜੋ)"</string>
-</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pl/strings.xml
index e8d7fb7dacc8..c027d5266928 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pl/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ukryj (unikaj wyświetlania aplikacji w obszarze wycięcia)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderuj aplikacje pod obszarem wycięcia"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rBR/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rBR/strings.xml
index b5364e996b91..d09ed97121fa 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rBR/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rBR/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ocultar (evitar apps na região recortada)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar apps abaixo da área de corte"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rPT/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rPT/strings.xml
index e9467a2879c4..d38ce43204d2 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rPT/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rPT/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ocultar (evitar apps na área de recorte)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar apps abaixo da área de recorte"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt/strings.xml
index b5364e996b91..d09ed97121fa 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ocultar (evitar apps na região recortada)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar apps abaixo da área de corte"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml
index 9aefb31c69c6..6e5947c0d753 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ascundeți (se evită aplicațiile în regiunea decupată)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Redați aplicațiile sub zona de decupaj"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ru/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ru/strings.xml
index 8335c77fc86d..c7f54bbff6a7 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ru/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ru/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Скрыть (не показывать приложения в вырезе на экране)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Отображать приложения под вырезом"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-si/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-si/strings.xml
index d21b02c04bdf..4a14a360e857 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-si/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-si/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"සඟවන්න (කටවුට් කලාපයෙහි යෙදුම් වළක්වන්න)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"කටවුට් ප්‍රදේශයට පහළින් යෙදුම් විදහන්න"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sk/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sk/strings.xml
index dfd01afb4c4b..98b82e636392 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sk/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sk/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Skryť (nezobrazovať aplikácie v oblasti výrezu)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Vykresľovať aplikácie pod oblasťou výrezu"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sl/strings.xml
index 704dfbbfb99f..dcf0c842cd36 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sl/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Skrij (izogibaj se aplikacijam na območju zareze)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Upodobitev aplikacij pod predelom zareze zaslona"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sq/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sq/strings.xml
index 8035d7f26ffa..d7b0676970b8 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sq/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sq/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Fshih (shmang aplikacionet në zonën e prerë)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Paraqiti aplikacionet poshtë zonës së prerjes"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sr/strings.xml
index c835b3582e25..c2b611e70da9 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sr/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sr/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Сакриј (избегавај апликације у изрезаној области)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Приказуј апликације испод области изреза"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sv/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sv/strings.xml
index a8fd15730ba4..3007ffb99e10 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sv/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sv/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Dölj (visa inte appar i skärmutskärningen)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Visa appar under skärmutskärningens område"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sw/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sw/strings.xml
index 57ef68437013..b605554b46f3 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sw/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sw/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ficha (epuka programu katika eneo lenye pengo)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Usionyeshe programu chini ya eneo lenye pengo"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ta/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ta/strings.xml
index c0506cf7df5e..c4d06fb68564 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ta/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ta/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"மறை (திரை மறையும் பகுதியில் ஆப்ஸைக் காட்ட வேண்டாம்)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"கட் அவுட் பகுதிக்குள்ளாக ஆப்ஸை ரெண்டர் செய்"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml
deleted file mode 100644
index db2a79787978..000000000000
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"దాచండి (కట్అవుట్ ప్రాంతంలో యాప్‌లను నివారించండి)"</string>
-</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-th/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-th/strings.xml
index 09d597dd456d..9a302507411a 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-th/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-th/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"ซ่อน (หลีกเลี่ยงการแสดงแอปในภูมิภาคที่ถูกตัดออก)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"แสดงผลแอปใต้บริเวณรอยบาก"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tl/strings.xml
index 6b1c3720ce8b..a3d4a3afe376 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tl/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Itago (iwasan ang mga app sa rehiyon ng cutout)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"I-render ang mga app sa ibaba ng lugar ng cutout"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tr/strings.xml
index 991a8406808e..12e0f3019814 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tr/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tr/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Gizle (kesim bölgesindeki uygulamalardan kaçının)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Uygulamaları kesme alanının altında oluşturun"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uk/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uk/strings.xml
index 7d6c068fd7e0..08b1521a12a0 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uk/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uk/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Сховати (не показувати додатки з вирізаних регіонів)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Відображати додатки під областю вирізу екрана"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml
deleted file mode 100644
index 48c5d14498b1..000000000000
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"چھپائیں (کٹ آؤٹ والے علاقے میں ایپس سے اجتناب کریں)"</string>
-</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uz/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uz/strings.xml
index 13a56acbab51..7f6f2b45fbd2 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uz/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uz/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Berkitish (qirqilgan hudud ilovalariga diqqat qiling)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Ekran kesimi quyidagi ilovalarni renderlash"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-vi/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-vi/strings.xml
index 221786294eb5..a7d54fbae9f5 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-vi/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-vi/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ẩn (không hiện các ứng dụng ở vùng cắt)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Hiển thị các ứng dụng bên dưới khu vực có vết cắt"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rCN/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rCN/strings.xml
index 3d672b4c086f..f596520fad30 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rCN/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rCN/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"隐藏(避免应用显示在凹口区域)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"在刘海区域下方呈现应用"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rHK/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rHK/strings.xml
index 7f37f3bfb488..ddb1df77b00c 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rHK/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rHK/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"隱藏 (避免將應用程式置於凹口區域)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"在凹口區域下方輸出應用程式"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rTW/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rTW/strings.xml
index ff50ddbdff94..7aad79c11bf2 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rTW/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rTW/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"隱藏 (避免在螢幕凹口顯示應用程式的內容)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"在螢幕凹口底下顯示應用程式畫面"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zu/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zu/strings.xml
index d6d772777d92..d861c5e60708 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zu/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zu/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Fihla (gwema ama-app kwisifunda esikhishiwe)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Nikezela ngama-app angaphansi kwendawo yokukhipha"</string>
</resources>
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 4e14411dd06e..acbf4875ae8d 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2186,10 +2186,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
return false;
}
- if (!ri.activityInfo.isEnabled()) {
- return false;
- }
-
ComponentName componentName = new ComponentName(ri.activityInfo.packageName,
ri.activityInfo.name);
ProviderId providerId = new ProviderId(ri.activityInfo.applicationInfo.uid, componentName);
diff --git a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
index ba7f44f2818b..1da45bd49767 100644
--- a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
@@ -305,6 +305,10 @@ public abstract class AbstractLocationProvider {
setState(state -> state.withIdentity(identity));
}
+ public final Set<String> getExtraAttributionTags() {
+ return mInternalState.get().state.extraAttributionTags;
+ }
+
/**
* Call this method to report a change in the provider's extra attribution tags.
*/
diff --git a/services/core/java/com/android/server/location/provider/MockableLocationProvider.java b/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
index 81936440f6a7..021e8dbdb44e 100644
--- a/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
@@ -32,6 +32,7 @@ import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collections;
+import java.util.Set;
/**
* Represents a location provider that may switch between a mock implementation and a real
@@ -296,6 +297,10 @@ public class MockableLocationProvider extends AbstractLocationProvider {
if (identity != null) {
pw.println("identity=" + identity);
}
+ Set<String> extraAttributionTags = getExtraAttributionTags();
+ if (!extraAttributionTags.isEmpty()) {
+ pw.println("extra attribution tags=" + extraAttributionTags);
+ }
ProviderProperties properties = getProperties();
if (properties != null) {
pw.println("properties=" + properties);
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
index 5df78704d002..a9641f0f1c1b 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
@@ -17,6 +17,7 @@
package com.android.server.location.provider.proxy;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+import static com.android.server.location.LocationManagerService.TAG;
import android.annotation.Nullable;
import android.content.Context;
@@ -32,6 +33,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.server.FgThread;
@@ -44,6 +46,7 @@ import com.android.server.servicewatcher.ServiceWatcher.ServiceListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -78,6 +81,7 @@ public class ProxyLocationProvider extends AbstractLocationProvider implements
final Context mContext;
final ServiceWatcher mServiceWatcher;
+ final String mName;
@GuardedBy("mLock")
final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0);
@@ -101,6 +105,7 @@ public class ProxyLocationProvider extends AbstractLocationProvider implements
mServiceWatcher = ServiceWatcher.create(context, provider,
new CurrentUserServiceSupplier(context, action, enableOverlayResId,
nonOverlayPackageResId), this);
+ mName = provider;
mProxy = null;
mRequest = ProviderRequest.EMPTY_REQUEST;
@@ -249,6 +254,8 @@ public class ProxyLocationProvider extends AbstractLocationProvider implements
String tagsStr = mBoundServiceInfo.getMetadata().getString(EXTRA_LOCATION_TAGS);
if (!TextUtils.isEmpty(tagsStr)) {
attributionTags = tagsStr.split(LOCATION_TAGS_SEPARATOR);
+ Log.i(TAG, mName + " provider loaded extra attribution tags: "
+ + Arrays.toString(attributionTags));
}
}
ArraySet<String> extraAttributionTags = new ArraySet<>(attributionTags);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 8202587ecf53..4b0eb6546888 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -3760,11 +3760,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return true;
}
- // Retrying commit.
- if (mIncrementalFileStorages != null) {
- return false;
- }
-
final List<InstallationFileParcel> addedFiles = new ArrayList<>();
final List<String> removedFiles = new ArrayList<>();
@@ -3925,18 +3920,24 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
(pkgInfo != null && pkgInfo.applicationInfo != null) ? new File(
pkgInfo.applicationInfo.getCodePath()).getParentFile() : null;
- mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir,
- inheritedDir, params, statusListener, healthCheckParams, healthListener,
- addedFiles, perUidReadTimeouts,
- new IPackageLoadingProgressCallback.Stub() {
- @Override
- public void onPackageLoadingProgressChanged(float progress) {
- synchronized (mProgressLock) {
- mIncrementalProgress = progress;
- computeProgressLocked(true);
+ if (mIncrementalFileStorages == null) {
+ mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext,
+ stageDir, inheritedDir, params, statusListener, healthCheckParams,
+ healthListener, addedFiles, perUidReadTimeouts,
+ new IPackageLoadingProgressCallback.Stub() {
+ @Override
+ public void onPackageLoadingProgressChanged(float progress) {
+ synchronized (mProgressLock) {
+ mIncrementalProgress = progress;
+ computeProgressLocked(true);
+ }
}
- }
- });
+ });
+ } else {
+ // Retrying commit.
+ mIncrementalFileStorages.startLoading(params, statusListener, healthCheckParams,
+ healthListener, perUidReadTimeouts);
+ }
return false;
} catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c812fc8b7081..a8cc5fdf884d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -23607,11 +23607,6 @@ public class PackageManagerService extends IPackageManager.Stub
throw new IllegalArgumentException("Must specify a component");
}
- boolean componentExists = mComponentResolver.componentExists(componentName);
- if (!componentExists) {
- throw new IllegalArgumentException("Component " + componentName + " not found");
- }
-
int callingUid = Binder.getCallingUid();
String componentPkgName = componentName.getPackageName();
@@ -23643,6 +23638,10 @@ public class PackageManagerService extends IPackageManager.Stub
"Changing the label is not allowed for " + componentName);
}
+ if (!mComponentResolver.componentExists(componentName)) {
+ throw new IllegalArgumentException("Component " + componentName + " not found");
+ }
+
if (!pkgSetting.overrideNonLocalizedLabelAndIcon(componentName, nonLocalizedLabel,
icon, userId)) {
// Nothing changed
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 4bc87a273084..7aa1c3ab8154 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3997,15 +3997,18 @@ public final class Settings implements Watchable, Snappable {
final int uninstallReason = (shouldMaybeInstall && !shouldReallyInstall) ?
UNINSTALL_REASON_USER_TYPE : UNINSTALL_REASON_UNKNOWN;
ps.setUninstallReason(uninstallReason, userHandle);
- if (!shouldReallyInstall) {
+ if (shouldReallyInstall) {
+ // Need to create a data directory for all apps installed for this user.
+ // Accumulate all required args and call the installer after mPackages lock
+ // has been released
+ final String seInfo = AndroidPackageUtils.getSeInfo(ps.pkg, ps);
+ batch.createAppData(ps.volumeUuid, ps.name, userHandle,
+ StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE,
+ ps.appId, seInfo, ps.pkg.getTargetSdkVersion());
+ } else {
+ // Make sure the app is excluded from storage mapping for this user
writeKernelMappingLPr(ps);
}
- // Need to create a data directory for all apps under this user. Accumulate all
- // required args and call the installer after mPackages lock has been released
- final String seInfo = AndroidPackageUtils.getSeInfo(ps.pkg, ps);
- batch.createAppData(ps.volumeUuid, ps.name, userHandle,
- StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE, ps.appId,
- seInfo, ps.pkg.getTargetSdkVersion());
}
}
t.traceBegin("createAppData");
diff --git a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
index f411c98433cf..901f96f7054b 100644
--- a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
+++ b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
@@ -61,7 +61,7 @@ public class ShortcutBitmapSaver {
* Before saving shortcuts.xml, and returning icons to the launcher, we wait for all pending
* saves to finish. However if it takes more than this long, we just give up and proceed.
*/
- private final long SAVE_WAIT_TIMEOUT_MS = 30 * 1000;
+ private final long SAVE_WAIT_TIMEOUT_MS = 5 * 1000;
private final ShortcutService mService;
@@ -281,7 +281,7 @@ public class ShortcutBitmapSaver {
}
final String path = file.getAbsolutePath();
- mService.postValue(shortcut, si -> si.setBitmapPath(path));
+ shortcut.setBitmapPath(path);
} catch (IOException | RuntimeException e) {
Slog.e(ShortcutService.TAG, "Unable to write bitmap to file", e);
@@ -296,14 +296,12 @@ public class ShortcutBitmapSaver {
Slog.d(TAG, "Saved bitmap.");
}
if (shortcut != null) {
- mService.postValue(shortcut, si -> {
- if (si.getBitmapPath() == null) {
- removeIcon(si);
- }
+ if (shortcut.getBitmapPath() == null) {
+ removeIcon(shortcut);
+ }
- // Whatever happened, remove this flag.
- si.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
- });
+ // Whatever happened, remove this flag.
+ shortcut.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
}
}
return true;
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1e9d7e1f8ad2..5f1027797292 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1208,16 +1208,6 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
- void postValue(@NonNull final ShortcutInfo shortcutInfo,
- @NonNull final Consumer<ShortcutInfo> cb) {
- final String pkg = shortcutInfo.getPackage();
- final int userId = shortcutInfo.getUserId();
- final String id = shortcutInfo.getId();
- synchronized (mLock) {
- getPackageShortcutsLocked(pkg, userId).mutateShortcut(id, shortcutInfo, cb);
- }
- }
-
/** Return the last reset time. */
@GuardedBy("mLock")
long getLastResetTimeLocked() {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 92b6a0818de8..a391dbc1fa47 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -17,7 +17,9 @@
package com.android.server.pm.permission;
import static android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY;
+import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.RECORD_AUDIO;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_ERRORED;
@@ -148,6 +150,7 @@ import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.HotwordDetectionServiceProvider;
import com.android.server.pm.permission.PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
@@ -308,6 +311,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@NonNull
private final OnPermissionChangeListeners mOnPermissionChangeListeners;
+ @Nullable
+ private HotwordDetectionServiceProvider mHotwordDetectionServiceProvider;
+
// TODO: Take a look at the methods defined in the callback.
// The callback was initially created to support the split between permission
// manager and the package manager. However, it's started to be used for other
@@ -5200,6 +5206,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public int[] getGidsForUid(int uid) {
return PermissionManagerService.this.getGidsForUid(uid);
}
+
+ @Override
+ public void setHotwordDetectionServiceProvider(HotwordDetectionServiceProvider provider) {
+ mHotwordDetectionServiceProvider = provider;
+ }
+
+ @Override
+ public HotwordDetectionServiceProvider getHotwordDetectionServiceProvider() {
+ return mHotwordDetectionServiceProvider;
+ }
}
/**
@@ -5476,10 +5492,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private final @NonNull Context mContext;
private final @NonNull AppOpsManager mAppOpsManager;
+ private final @NonNull PermissionManagerServiceInternal mPermissionManagerServiceInternal;
PermissionCheckerService(@NonNull Context context) {
mContext = context;
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ mPermissionManagerServiceInternal =
+ LocalServices.getService(PermissionManagerServiceInternal.class);
}
@Override
@@ -5492,8 +5511,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
Objects.requireNonNull(attributionSourceState);
final AttributionSource attributionSource = new AttributionSource(
attributionSourceState);
- final int result = checkPermission(mContext, permission, attributionSource, message,
- forDataDelivery, startDataDelivery, fromDatasource, attributedOp);
+ final int result = checkPermission(mContext, mPermissionManagerServiceInternal,
+ permission, attributionSource, message, forDataDelivery, startDataDelivery,
+ fromDatasource, attributedOp);
// Finish any started op if some step in the attribution chain failed.
if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED
&& result != PermissionChecker.PERMISSION_SOFT_DENIED) {
@@ -5582,10 +5602,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@PermissionCheckerManager.PermissionResult
- private static int checkPermission(@NonNull Context context, @NonNull String permission,
- @NonNull AttributionSource attributionSource, @Nullable String message,
- boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource,
- int attributedOp) {
+ private static int checkPermission(@NonNull Context context,
+ @NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
+ @NonNull String permission, @NonNull AttributionSource attributionSource,
+ @Nullable String message, boolean forDataDelivery, boolean startDataDelivery,
+ boolean fromDatasource, int attributedOp) {
PermissionInfo permissionInfo = sPlatformPermissions.get(permission);
if (permissionInfo == null) {
@@ -5602,22 +5623,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (permissionInfo.isAppOp()) {
- return checkAppOpPermission(context, permission, attributionSource, message,
- forDataDelivery, fromDatasource);
+ return checkAppOpPermission(context, permissionManagerServiceInt, permission,
+ attributionSource, message, forDataDelivery, fromDatasource);
}
if (permissionInfo.isRuntime()) {
- return checkRuntimePermission(context, permission, attributionSource, message,
- forDataDelivery, startDataDelivery, fromDatasource, attributedOp);
+ return checkRuntimePermission(context, permissionManagerServiceInt, permission,
+ attributionSource, message, forDataDelivery, startDataDelivery,
+ fromDatasource, attributedOp);
}
- if (!fromDatasource && !checkPermission(context, permission, attributionSource.getUid(),
+ if (!fromDatasource && !checkPermission(context, permissionManagerServiceInt,
+ permission, attributionSource.getUid(),
attributionSource.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
if (attributionSource.getNext() != null) {
- return checkPermission(context, permission, attributionSource.getNext(), message,
- forDataDelivery, startDataDelivery, /*fromDatasource*/ false, attributedOp);
+ return checkPermission(context, permissionManagerServiceInt, permission,
+ attributionSource.getNext(), message, forDataDelivery, startDataDelivery,
+ /*fromDatasource*/ false, attributedOp);
}
return PermissionChecker.PERMISSION_GRANTED;
@@ -5625,6 +5649,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@PermissionCheckerManager.PermissionResult
private static int checkAppOpPermission(@NonNull Context context,
+ @NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
@NonNull String permission, @NonNull AttributionSource attributionSource,
@Nullable String message, boolean forDataDelivery, boolean fromDatasource) {
final int op = AppOpsManager.permissionToOpCode(permission);
@@ -5668,13 +5693,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
case AppOpsManager.MODE_DEFAULT: {
- if (!skipCurrentChecks && !checkPermission(context, permission,
- attributionSource.getUid(), attributionSource
- .getRenouncedPermissions())) {
+ if (!skipCurrentChecks && !checkPermission(context,
+ permissionManagerServiceInt, permission, attributionSource.getUid(),
+ attributionSource.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
- if (next != null && !checkPermission(context, permission,
- next.getUid(), next.getRenouncedPermissions())) {
+ if (next != null && !checkPermission(context, permissionManagerServiceInt,
+ permission, next.getUid(), next.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
}
@@ -5689,6 +5714,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private static int checkRuntimePermission(@NonNull Context context,
+ @NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
@NonNull String permission, @NonNull AttributionSource attributionSource,
@Nullable String message, boolean forDataDelivery, boolean startDataDelivery,
boolean fromDatasource, int attributedOp) {
@@ -5713,13 +5739,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
// If we already checked the permission for this one, skip the work
- if (!skipCurrentChecks && !checkPermission(context, permission,
- current.getUid(), current.getRenouncedPermissions())) {
+ if (!skipCurrentChecks && !checkPermission(context, permissionManagerServiceInt,
+ permission, current.getUid(), current.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
- if (next != null && !checkPermission(context, permission,
- next.getUid(), next.getRenouncedPermissions())) {
+ if (next != null && !checkPermission(context, permissionManagerServiceInt,
+ permission, next.getUid(), next.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
@@ -5774,10 +5800,26 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- private static boolean checkPermission(@NonNull Context context, @NonNull String permission,
- int uid, @NonNull Set<String> renouncedPermissions) {
- final boolean permissionGranted = context.checkPermission(permission, /*pid*/ -1,
+ private static boolean checkPermission(@NonNull Context context,
+ @NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
+ @NonNull String permission, int uid, @NonNull Set<String> renouncedPermissions) {
+ boolean permissionGranted = context.checkPermission(permission, /*pid*/ -1,
uid) == PackageManager.PERMISSION_GRANTED;
+
+ // Override certain permissions checks for the HotwordDetectionService. This service is
+ // an isolated service, which ordinarily cannot hold permissions.
+ // There's probably a cleaner, more generalizable way to do this. For now, this is
+ // the only use case for this, so simply override here.
+ if (!permissionGranted
+ && Process.isIsolated(uid) // simple check which fails-fast for the common case
+ && (permission.equals(RECORD_AUDIO)
+ || permission.equals(CAPTURE_AUDIO_HOTWORD))) {
+ HotwordDetectionServiceProvider hotwordServiceProvider =
+ permissionManagerServiceInt.getHotwordDetectionServiceProvider();
+ permissionGranted = hotwordServiceProvider != null
+ && uid == hotwordServiceProvider.getUid();
+ }
+
if (permissionGranted && renouncedPermissions.contains(permission)
&& context.checkPermission(Manifest.permission.RENOUNCE_PERMISSIONS,
/*pid*/ -1, uid) == PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 895cabc33bab..f4fb8102d922 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -428,4 +428,28 @@ public interface PermissionManagerServiceInternal extends PermissionManagerInter
}
}
}
+
+ /**
+ * Sets the provider of the currently active HotwordDetectionService.
+ *
+ * @see HotwordDetectionServiceProvider
+ */
+ void setHotwordDetectionServiceProvider(@Nullable HotwordDetectionServiceProvider provider);
+
+ /**
+ * Gets the provider of the currently active HotwordDetectionService.
+ *
+ * @see HotwordDetectionServiceProvider
+ */
+ @Nullable
+ HotwordDetectionServiceProvider getHotwordDetectionServiceProvider();
+
+ /**
+ * Provides the uid of the currently active
+ * {@link android.service.voice.HotwordDetectionService}, which should be granted RECORD_AUDIO
+ * and CAPTURE_AUDIO_HOTWORD permissions.
+ */
+ interface HotwordDetectionServiceProvider {
+ int getUid();
+ }
}
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index 70b5c62a4973..94005b2c8361 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -33,7 +33,10 @@ import android.content.pm.ResolveInfo;
import android.location.LocationManagerInternal;
import android.net.Uri;
import android.os.IBinder;
+import android.os.Process;
import android.os.UserHandle;
+import android.service.voice.VoiceInteractionManagerInternal;
+import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -78,6 +81,9 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
@NonNull
private final RoleManager mRoleManager;
+ @NonNull
+ private final VoiceInteractionManagerInternal mVoiceInteractionManagerInternal;
+
/**
* The locking policy around the location tags is a bit special. Since we want to
* avoid grabbing the lock on every op note we are taking the approach where the
@@ -101,6 +107,8 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
public AppOpsPolicy(@NonNull Context context) {
mContext = context;
mRoleManager = mContext.getSystemService(RoleManager.class);
+ mVoiceInteractionManagerInternal = LocalServices.getService(
+ VoiceInteractionManagerInternal.class);
final LocationManagerInternal locationManagerInternal = LocalServices.getService(
LocationManagerInternal.class);
@@ -150,7 +158,7 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
public int checkOperation(int code, int uid, String packageName,
@Nullable String attributionTag, boolean raw,
QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) {
- return superImpl.apply(code, uid, packageName, attributionTag, raw);
+ return superImpl.apply(code, resolveUid(code, uid), packageName, attributionTag, raw);
}
@Override
@@ -164,8 +172,8 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable
String message, boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer,
String, String, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
- return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag), uid,
- packageName, attributionTag, shouldCollectAsyncNotedOp,
+ return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag),
+ resolveUid(code, uid), packageName, attributionTag, shouldCollectAsyncNotedOp,
message, shouldCollectMessage);
}
@@ -190,8 +198,9 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
String, Boolean, Boolean, String, Boolean, Integer, Integer,
SyncNotedAppOp> superImpl) {
return superImpl.apply(token, resolveDatasourceOp(code, uid, packageName, attributionTag),
- uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp,
- message, shouldCollectMessage, attributionFlags, attributionChainId);
+ resolveUid(code, uid), packageName, attributionTag, startIfModeDefault,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
+ attributionChainId);
}
@Override
@@ -404,4 +413,23 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
}
return code;
}
+
+ private int resolveUid(int code, int uid) {
+ // The HotwordDetectionService is an isolated service, which ordinarily cannot hold
+ // permissions. So we allow it to assume the owning package identity for certain
+ // operations.
+ // Note: The package name coming from the audio server is already the one for the owning
+ // package, so we don't need to modify it.
+ if (Process.isIsolated(uid) // simple check which fails-fast for the common case
+ && (code == AppOpsManager.OP_RECORD_AUDIO
+ || code == AppOpsManager.OP_RECORD_AUDIO_HOTWORD)) {
+ final HotwordDetectionServiceIdentity hotwordDetectionServiceIdentity =
+ mVoiceInteractionManagerInternal.getHotwordDetectionServiceIdentity();
+ if (hotwordDetectionServiceIdentity != null
+ && uid == hotwordDetectionServiceIdentity.getIsolatedUid()) {
+ uid = hotwordDetectionServiceIdentity.getOwnerUid();
+ }
+ }
+ return uid;
+ }
}
diff --git a/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java b/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
index e718ba3b17cf..631be380e2eb 100644
--- a/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
+++ b/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
@@ -135,6 +135,7 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements
if (forceRebind || !Objects.equals(mServiceConnection.getBoundServiceInfo(),
newBoundServiceInfo)) {
+ Log.i(TAG, "[" + mTag + "] chose new implementation " + newBoundServiceInfo);
MyServiceConnection oldServiceConnection = mServiceConnection;
MyServiceConnection newServiceConnection = new MyServiceConnection(newBoundServiceInfo);
mServiceConnection = newServiceConnection;
@@ -196,7 +197,9 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements
return;
}
- Log.i(TAG, "[" + mTag + "] binding to " + mBoundServiceInfo);
+ if (D) {
+ Log.d(TAG, "[" + mTag + "] binding to " + mBoundServiceInfo);
+ }
Intent bindIntent = new Intent(mBoundServiceInfo.getAction()).setComponent(
mBoundServiceInfo.getComponentName());
@@ -255,9 +258,7 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Preconditions.checkState(mBinder == null);
- if (D) {
- Log.d(TAG, "[" + mTag + "] connected to " + component.toShortString());
- }
+ Log.i(TAG, "[" + mTag + "] connected to " + component.toShortString());
mBinder = binder;
@@ -280,9 +281,7 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements
return;
}
- if (D) {
- Log.d(TAG, "[" + mTag + "] disconnected from " + mBoundServiceInfo);
- }
+ Log.i(TAG, "[" + mTag + "] disconnected from " + mBoundServiceInfo);
mBinder = null;
if (mServiceListener != null) {
@@ -294,9 +293,11 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements
public final void onBindingDied(ComponentName component) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- Log.i(TAG, "[" + mTag + "] " + mBoundServiceInfo + " died");
+ Log.w(TAG, "[" + mTag + "] " + mBoundServiceInfo + " died");
- onServiceChanged(true);
+ // introduce a small delay to prevent spamming binding over and over, since the likely
+ // cause of a binding dying is some package event that may take time to recover from
+ mHandler.postDelayed(() -> onServiceChanged(true), 500);
}
@Override
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index c888e545b24e..53f1035ee422 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 = wpData.mHeight != cropHint.height()
+ needScale = cropHint.height() > wpData.mHeight
|| 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.JPEG, 100, bos);
+ finalCrop.compress(Bitmap.CompressFormat.PNG, 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/Task.java b/services/core/java/com/android/server/wm/Task.java
index 82d1c04591a6..7af8d8bb5200 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -7653,17 +7653,23 @@ class Task extends WindowContainer<WindowContainer> {
void clearLastRecentsAnimationTransaction() {
mLastRecentsAnimationTransaction = null;
mLastRecentsAnimationOverlay = null;
- // reset also the transform introduced by mLastRecentsAnimationTransaction
- getPendingTransaction().setMatrix(mSurfaceControl, Matrix.IDENTITY_MATRIX, new float[9]);
+ // reset also the crop and transform introduced by mLastRecentsAnimationTransaction
+ Rect bounds = getBounds();
+ getPendingTransaction().setMatrix(mSurfaceControl, Matrix.IDENTITY_MATRIX, new float[9])
+ .setWindowCrop(mSurfaceControl, bounds.width(), bounds.height());
}
void maybeApplyLastRecentsAnimationTransaction() {
if (mLastRecentsAnimationTransaction != null) {
+ final SurfaceControl.Transaction tx = getPendingTransaction();
if (mLastRecentsAnimationOverlay != null) {
- getPendingTransaction().reparent(mLastRecentsAnimationOverlay, mSurfaceControl);
+ tx.reparent(mLastRecentsAnimationOverlay, mSurfaceControl);
}
PictureInPictureSurfaceTransaction.apply(mLastRecentsAnimationTransaction,
- mSurfaceControl, getPendingTransaction());
+ mSurfaceControl, tx);
+ // If we are transferring the transform from the root task entering PIP, then also show
+ // the new task immediately
+ tx.show(mSurfaceControl);
mLastRecentsAnimationTransaction = null;
mLastRecentsAnimationOverlay = null;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 642ce1b34769..299cde8ad1d8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3928,7 +3928,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void notifyInsetsChanged() {
ProtoLog.d(WM_DEBUG_IME, "notifyInsetsChanged for %s ", this);
try {
- mClient.insetsChanged(getCompatInsetsState());
+ mClient.insetsChanged(getCompatInsetsState(),
+ hasMoved(),
+ mWindowFrames.isFrameSizeChangeReported());
} catch (RemoteException e) {
Slog.w(TAG, "Failed to deliver inset state change w=" + this, e);
}
@@ -3944,7 +3946,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
getDisplayContent().getInsetsStateController();
try {
mClient.insetsControlChanged(getCompatInsetsState(),
- stateController.getControlsForDispatch(this));
+ stateController.getControlsForDispatch(this),
+ hasMoved(),
+ mWindowFrames.isFrameSizeChangeReported());
} catch (RemoteException e) {
Slog.w(TAG, "Failed to deliver inset state change to w=" + this, e);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 228bc0ecc051..1d27655055a0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -22,6 +22,7 @@ import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
@@ -990,13 +991,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
Bundle prevRestrictions) {
- final boolean newlyDisallowed =
- newRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE);
- final boolean previouslyDisallowed =
- prevRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE);
- final boolean restrictionChanged = (newlyDisallowed != previouslyDisallowed);
+ resetCrossProfileIntentFiltersIfNeeded(userId, newRestrictions, prevRestrictions);
+ resetUserVpnIfNeeded(userId, newRestrictions, prevRestrictions);
+ }
- if (restrictionChanged) {
+ private void resetUserVpnIfNeeded(
+ int userId, Bundle newRestrictions, Bundle prevRestrictions) {
+ final boolean newlyEnforced =
+ !prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_VPN)
+ && newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_VPN);
+ if (newlyEnforced) {
+ mDpms.clearUserConfiguredVpns(userId);
+ }
+ }
+
+ private void resetCrossProfileIntentFiltersIfNeeded(
+ int userId, Bundle newRestrictions, Bundle prevRestrictions) {
+ if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions,
+ UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE)) {
final int parentId = mUserManagerInternal.getProfileParentId(userId);
if (parentId == userId) {
return;
@@ -1007,13 +1019,55 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Slogf.i(LOG_TAG, "Resetting cross-profile intent filters on restriction "
+ "change");
mDpms.resetDefaultCrossProfileIntentFilters(parentId);
- mContext.sendBroadcastAsUser(new Intent(
- DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_APPLIED),
+ mContext.sendBroadcastAsUser(
+ new Intent(DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_APPLIED),
UserHandle.of(userId));
}
}
}
+ private void clearUserConfiguredVpns(int userId) {
+ final String adminConfiguredVpnPkg;
+ synchronized (getLockObject()) {
+ final ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
+ if (owner == null) {
+ Slogf.wtf(LOG_TAG, "Admin not found");
+ return;
+ }
+ adminConfiguredVpnPkg = owner.mAlwaysOnVpnPackage;
+ }
+
+ // Clear always-on configuration if it wasn't set by the admin.
+ if (adminConfiguredVpnPkg == null) {
+ mInjector.getVpnManager().setAlwaysOnVpnPackageForUser(userId, null, false, null);
+ }
+
+ // Clear app authorizations to establish VPNs. When DISALLOW_CONFIG_VPN is enforced apps
+ // won't be able to get those authorizations unless it is configured by an admin.
+ final List<AppOpsManager.PackageOps> allVpnOps = mInjector.getAppOpsManager()
+ .getPackagesForOps(new int[] {AppOpsManager.OP_ACTIVATE_VPN});
+ if (allVpnOps == null) {
+ return;
+ }
+ for (AppOpsManager.PackageOps pkgOps : allVpnOps) {
+ if (UserHandle.getUserId(pkgOps.getUid()) != userId
+ || pkgOps.getPackageName().equals(adminConfiguredVpnPkg)) {
+ continue;
+ }
+ if (pkgOps.getOps().size() != 1) {
+ Slogf.wtf(LOG_TAG, "Unexpected number of ops returned");
+ continue;
+ }
+ final @Mode int mode = pkgOps.getOps().get(0).getMode();
+ if (mode == MODE_ALLOWED) {
+ Slogf.i(LOG_TAG, String.format("Revoking VPN authorization for package %s uid %d",
+ pkgOps.getPackageName(), pkgOps.getUid()));
+ mInjector.getAppOpsManager().setMode(AppOpsManager.OP_ACTIVATE_VPN, pkgOps.getUid(),
+ pkgOps.getPackageName(), MODE_DEFAULT);
+ }
+ }
+ }
+
private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener {
@Override
@@ -6559,6 +6613,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_ALWAYS_ON_VPN_PACKAGE);
+ if (vpnPackage == null) {
+ final String prevVpnPackage;
+ synchronized (getLockObject()) {
+ prevVpnPackage = getProfileOwnerOrDeviceOwnerLocked(caller).mAlwaysOnVpnPackage;
+ // If the admin is clearing VPN package but hasn't configure any VPN previously,
+ // ignore it so that it doesn't interfere with user-configured VPNs.
+ if (TextUtils.isEmpty(prevVpnPackage)) {
+ return true;
+ }
+ }
+ revokeVpnAuthorizationForPackage(prevVpnPackage, caller.getUserId());
+ }
+
final int userId = caller.getUserId();
mInjector.binderWithCleanCallingIdentity(() -> {
if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) {
@@ -6581,14 +6648,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
userId, vpnPackage, lockdown, lockdownAllowlist)) {
throw new UnsupportedOperationException();
}
- DevicePolicyEventLogger
- .createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE)
- .setAdmin(caller.getComponentName())
- .setStrings(vpnPackage)
- .setBoolean(lockdown)
- .setInt(lockdownAllowlist != null ? lockdownAllowlist.size() : 0)
- .write();
});
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE)
+ .setAdmin(caller.getComponentName())
+ .setStrings(vpnPackage)
+ .setBoolean(lockdown)
+ .setInt(lockdownAllowlist != null ? lockdownAllowlist.size() : 0)
+ .write();
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage)
@@ -6601,6 +6668,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return true;
}
+ private void revokeVpnAuthorizationForPackage(String vpnPackage, int userId) {
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ try {
+ final ApplicationInfo ai = mIPackageManager.getApplicationInfo(
+ vpnPackage, /* flags= */ 0, userId);
+ if (ai == null) {
+ Slogf.w(LOG_TAG, "Non-existent VPN package: " + vpnPackage);
+ } else {
+ mInjector.getAppOpsManager().setMode(AppOpsManager.OP_ACTIVATE_VPN,
+ ai.uid, vpnPackage, MODE_DEFAULT);
+ }
+ } catch (RemoteException e) {
+ Slogf.e(LOG_TAG, "Can't talk to package managed", e);
+ }
+ });
+ }
+
@Override
public String getAlwaysOnVpnPackage(ComponentName admin) throws SecurityException {
Objects.requireNonNull(admin, "ComponentName is null");
@@ -8390,12 +8474,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return who != null && who.equals(profileOwner);
}
- private boolean isProfileOwnerUncheckedLocked(ComponentName who, int userId) {
- ensureLocked();
- final ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId);
- return who != null && who.equals(profileOwner);
- }
-
/**
* Returns {@code true} if the provided caller identity is of a profile owner.
* @param caller identity of caller.
@@ -10005,14 +10083,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return true;
}
- private AccessibilityManager getAccessibilityManagerForUser(int userId) {
+ /**
+ * Invoke a method in AccessibilityManager ensuring the client is removed.
+ */
+ private <T> T withAccessibilityManager(
+ int userId, Function<AccessibilityManager, T> function) {
// Not using AccessibilityManager.getInstance because that guesses
// at the user you require based on callingUid and caches for a given
// process.
- IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
- IAccessibilityManager service = iBinder == null
+ final IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
+ final IAccessibilityManager service = iBinder == null
? null : IAccessibilityManager.Stub.asInterface(iBinder);
- return new AccessibilityManager(mContext, service, userId);
+ final AccessibilityManager am = new AccessibilityManager(mContext, service, userId);
+ try {
+ return function.apply(am);
+ } finally {
+ am.removeClient();
+ }
}
@Override
@@ -10025,22 +10112,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (packageList != null) {
int userId = caller.getUserId();
- List<AccessibilityServiceInfo> enabledServices = null;
+ final List<AccessibilityServiceInfo> enabledServices;
long id = mInjector.binderClearCallingIdentity();
try {
UserInfo user = getUserInfo(userId);
if (user.isManagedProfile()) {
userId = user.profileGroupId;
}
- AccessibilityManager accessibilityManager = getAccessibilityManagerForUser(userId);
- enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
- FEEDBACK_ALL_MASK);
+ enabledServices = withAccessibilityManager(userId,
+ am -> am.getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK));
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
if (enabledServices != null) {
- List<String> enabledPackages = new ArrayList<String>();
+ List<String> enabledPackages = new ArrayList<>();
for (AccessibilityServiceInfo service : enabledServices) {
enabledPackages.add(service.getResolveInfo().serviceInfo.packageName);
}
@@ -10122,10 +10208,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (user.isManagedProfile()) {
userId = user.profileGroupId;
}
- AccessibilityManager accessibilityManager =
- getAccessibilityManagerForUser(userId);
- List<AccessibilityServiceInfo> installedServices =
- accessibilityManager.getInstalledAccessibilityServiceList();
+ final List<AccessibilityServiceInfo> installedServices =
+ withAccessibilityManager(userId,
+ AccessibilityManager::getInstalledAccessibilityServiceList);
if (installedServices != null) {
for (AccessibilityServiceInfo service : installedServices) {
@@ -13660,16 +13745,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
+ " is not device owner");
}
- private ComponentName getOwnerComponent(String packageName, int userId) {
- if (isDeviceOwnerPackage(packageName, userId)) {
- return mOwners.getDeviceOwnerComponent();
- }
- if (isProfileOwnerPackage(packageName, userId)) {
- return mOwners.getProfileOwnerComponent(userId);
- }
- return null;
- }
-
/**
* Return device owner or profile owner set on a given user.
*/
@@ -17462,14 +17537,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean isUsbDataSignalingEnabled(String packageName) {
- final CallerIdentity caller = getCallerIdentity(packageName);
- Preconditions.checkCallAuthorization(
- isDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller),
- "USB data signaling can only be controlled by a device owner or "
- + "a profile owner on an organization-owned device.");
-
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(
+ getCallerIdentity(packageName));
return admin.mUsbDataSignalingEnabled;
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
index 48d2d73543fb..532823ad8367 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
@@ -18,8 +18,6 @@ package com.android.server.devicepolicy;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
-import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG;
-
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -142,9 +140,21 @@ public final class PersonalAppsSuspensionHelper {
}
private List<String> getAccessibilityServices() {
- final List<AccessibilityServiceInfo> accessibilityServiceInfos =
- getAccessibilityManagerForUser(mContext.getUserId())
- .getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
+ final List<AccessibilityServiceInfo> accessibilityServiceInfos;
+ // Not using AccessibilityManager.getInstance because that guesses
+ // at the user you require based on callingUid and caches for a given
+ // process.
+ final IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
+ final IAccessibilityManager service = iBinder == null
+ ? null : IAccessibilityManager.Stub.asInterface(iBinder);
+ final AccessibilityManager am =
+ new AccessibilityManager(mContext, service, mContext.getUserId());
+ try {
+ accessibilityServiceInfos = am.getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
+ } finally {
+ am.removeClient();
+ }
+
final List<String> result = new ArrayList<>();
for (final AccessibilityServiceInfo serviceInfo : accessibilityServiceInfos) {
final ComponentName componentName =
@@ -192,12 +202,6 @@ public final class PersonalAppsSuspensionHelper {
return resolveInfos != null && !resolveInfos.isEmpty();
}
- private AccessibilityManager getAccessibilityManagerForUser(int userId) {
- final IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
- final IAccessibilityManager service =
- iBinder == null ? null : IAccessibilityManager.Stub.asInterface(iBinder);
- return new AccessibilityManager(mContext, service, userId);
- }
void dump(IndentingPrintWriter pw) {
pw.println("PersonalAppsSuspensionHelper");
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 47d59b250e29..757c9dec06ed 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -89,6 +89,11 @@ struct Constants {
// Max interval after system invoked the DL when readlog collection can be enabled.
static constexpr auto readLogsMaxInterval = 2h;
+
+ // How long should we wait till dataLoader reports destroyed.
+ static constexpr auto destroyTimeout = 60s;
+
+ static constexpr auto anyStatus = INT_MIN;
};
static const Constants& constants() {
@@ -2554,7 +2559,7 @@ void IncrementalService::DataLoaderStub::cleanupResources() {
mControl = {};
mHealthControl = {};
mHealthListener = {};
- mStatusCondition.wait_until(lock, now + 60s, [this] {
+ mStatusCondition.wait_until(lock, now + Constants::destroyTimeout, [this] {
return mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
});
mStatusListener = {};
@@ -2754,8 +2759,16 @@ bool IncrementalService::DataLoaderStub::fsmStep() {
switch (targetStatus) {
case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
switch (currentStatus) {
+ case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE:
+ case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE:
+ destroy();
+ // DataLoader is broken, just assume it's destroyed.
+ compareAndSetCurrentStatus(currentStatus,
+ IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
+ return true;
case IDataLoaderStatusListener::DATA_LOADER_BINDING:
- setCurrentStatus(IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
+ compareAndSetCurrentStatus(currentStatus,
+ IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
return true;
default:
return destroy();
@@ -2776,7 +2789,11 @@ bool IncrementalService::DataLoaderStub::fsmStep() {
case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE:
// Before binding need to make sure we are unbound.
// Otherwise we'll get stuck binding.
- return destroy();
+ destroy();
+ // DataLoader is broken, just assume it's destroyed.
+ compareAndSetCurrentStatus(currentStatus,
+ IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
+ return true;
case IDataLoaderStatusListener::DATA_LOADER_DESTROYED:
case IDataLoaderStatusListener::DATA_LOADER_BINDING:
return bind();
@@ -2815,6 +2832,11 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount
}
void IncrementalService::DataLoaderStub::setCurrentStatus(int newStatus) {
+ compareAndSetCurrentStatus(Constants::anyStatus, newStatus);
+}
+
+void IncrementalService::DataLoaderStub::compareAndSetCurrentStatus(int expectedStatus,
+ int newStatus) {
int oldStatus, oldTargetStatus, newTargetStatus;
DataLoaderStatusListener listener;
{
@@ -2822,6 +2844,9 @@ void IncrementalService::DataLoaderStub::setCurrentStatus(int newStatus) {
if (mCurrentStatus == newStatus) {
return;
}
+ if (expectedStatus != Constants::anyStatus && expectedStatus != mCurrentStatus) {
+ return;
+ }
oldStatus = mCurrentStatus;
oldTargetStatus = mTargetStatus;
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 5de7325b3d28..b81e1b1b071c 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -255,6 +255,7 @@ private:
binder::Status onStatusChanged(MountId mount, int newStatus) final;
void setCurrentStatus(int newStatus);
+ void compareAndSetCurrentStatus(int expectedStatus, int newStatus);
sp<content::pm::IDataLoader> getDataLoader();
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 094c5fb36eea..59d96d2393ef 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -808,7 +808,9 @@ public:
METRICS_MILLIS_SINCE_OLDEST_PENDING_READ()
.c_str()),
&millisSinceOldestPendingRead));
- ASSERT_EQ(expectedMillisSinceOldestPendingRead, millisSinceOldestPendingRead);
+ // Allow 10ms.
+ ASSERT_LE(expectedMillisSinceOldestPendingRead, millisSinceOldestPendingRead);
+ ASSERT_GE(expectedMillisSinceOldestPendingRead + 10, millisSinceOldestPendingRead);
int storageHealthStatusCode = -1;
ASSERT_TRUE(
result.getInt(String16(BnIncrementalService::METRICS_STORAGE_HEALTH_STATUS_CODE()
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index d55d0600b7c9..ef1201e16ba0 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -254,6 +254,18 @@ public class DataManager {
return null;
}
+ ConversationInfo getConversationInfo(String packageName, int userId, String shortcutId) {
+ UserData userData = getUnlockedUserData(userId);
+ if (userData != null) {
+ PackageData packageData = userData.getPackageData(packageName);
+ // App may have been uninstalled.
+ if (packageData != null) {
+ return packageData.getConversationInfo(shortcutId);
+ }
+ }
+ return null;
+ }
+
@Nullable
private ConversationChannel getConversationChannel(String packageName, int userId,
String shortcutId, ConversationInfo conversationInfo) {
@@ -277,7 +289,7 @@ public class DataManager {
int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
NotificationChannel parentChannel =
mNotificationManagerInternal.getNotificationChannel(packageName, uid,
- conversationInfo.getParentNotificationChannelId());
+ conversationInfo.getNotificationChannelId());
NotificationChannelGroup parentChannelGroup = null;
if (parentChannel != null) {
parentChannelGroup =
@@ -302,7 +314,7 @@ public class DataManager {
String shortcutId = conversationInfo.getShortcutId();
ConversationChannel channel = getConversationChannel(packageData.getPackageName(),
packageData.getUserId(), shortcutId, conversationInfo);
- if (channel == null || channel.getParentNotificationChannel() == null) {
+ if (channel == null || channel.getNotificationChannel() == null) {
return;
}
conversationChannels.add(channel);
@@ -791,8 +803,8 @@ public class DataManager {
private boolean isCachedRecentConversation(ConversationInfo conversationInfo) {
return conversationInfo.isShortcutCachedForNotification()
- && conversationInfo.getNotificationChannelId() == null
- && conversationInfo.getParentNotificationChannelId() != null
+ && Objects.equals(conversationInfo.getNotificationChannelId(),
+ conversationInfo.getParentNotificationChannelId())
&& conversationInfo.getLastEventTimestamp() > 0L;
}
@@ -910,7 +922,7 @@ public class DataManager {
}
@VisibleForTesting
- NotificationListenerService getNotificationListenerServiceForTesting(@UserIdInt int userId) {
+ NotificationListener getNotificationListenerServiceForTesting(@UserIdInt int userId) {
return mNotificationListeners.get(userId);
}
@@ -1132,7 +1144,7 @@ public class DataManager {
}
@Override
- public void onNotificationPosted(StatusBarNotification sbn) {
+ public void onNotificationPosted(StatusBarNotification sbn, RankingMap map) {
if (sbn.getUser().getIdentifier() != mUserId) {
return;
}
@@ -1145,16 +1157,22 @@ public class DataManager {
});
if (packageData != null) {
+ Ranking rank = new Ranking();
+ map.getRanking(sbn.getKey(), rank);
ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId);
if (conversationInfo == null) {
return;
}
if (DEBUG) Log.d(TAG, "Last event from notification: " + sbn.getPostTime());
- ConversationInfo updated = new ConversationInfo.Builder(conversationInfo)
+ ConversationInfo.Builder updated = new ConversationInfo.Builder(conversationInfo)
.setLastEventTimestamp(sbn.getPostTime())
- .setParentNotificationChannelId(sbn.getNotification().getChannelId())
- .build();
- packageData.getConversationStore().addOrUpdate(updated);
+ .setNotificationChannelId(rank.getChannel().getId());
+ if (!TextUtils.isEmpty(rank.getChannel().getParentChannelId())) {
+ updated.setParentNotificationChannelId(rank.getChannel().getParentChannelId());
+ } else {
+ updated.setParentNotificationChannelId(sbn.getNotification().getChannelId());
+ }
+ packageData.getConversationStore().addOrUpdate(updated.build());
EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateEventHistory(
EventStore.CATEGORY_SHORTCUT_BASED, shortcutId);
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 6c5c1d4b59eb..b4f8b6edd139 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -16,6 +16,7 @@
package com.android.server.pm.test.override
+import android.app.PropertyInvalidatedCache
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
@@ -26,8 +27,10 @@ import android.util.ArrayMap
import com.android.server.pm.AppsFilter
import com.android.server.pm.ComponentResolver
import com.android.server.pm.PackageManagerService
+import com.android.server.pm.PackageManagerTracedLock
import com.android.server.pm.PackageSetting
import com.android.server.pm.Settings
+import com.android.server.pm.UserManagerInternal
import com.android.server.pm.UserManagerService
import com.android.server.pm.parsing.pkg.AndroidPackage
import com.android.server.pm.parsing.pkg.PackageImpl
@@ -42,6 +45,7 @@ import com.android.server.wm.ActivityTaskManagerInternal
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
+import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -63,6 +67,7 @@ class PackageManagerComponentLabelIconOverrideTest {
private const val VALID_PKG = "com.android.server.pm.test.override"
private const val SHARED_PKG = "com.android.server.pm.test.override.shared"
private const val INVALID_PKG = "com.android.server.pm.test.override.invalid"
+ private const val NON_EXISTENT_PKG = "com.android.server.pm.test.override.nonexistent"
private const val SEND_PENDING_BROADCAST = 1 // PackageManagerService.SEND_PENDING_BROADCAST
@@ -94,7 +99,8 @@ class PackageManagerComponentLabelIconOverrideTest {
// Start with an array of the simplest known inputs and expected outputs
Params(VALID_PKG, AppType.SYSTEM_APP, Result.Changed),
Params(SHARED_PKG, AppType.SYSTEM_APP, Result.Changed),
- Params(INVALID_PKG, AppType.SYSTEM_APP, SecurityException::class.java)
+ Params(INVALID_PKG, AppType.SYSTEM_APP, SecurityException::class.java),
+ Params(NON_EXISTENT_PKG, AppType.SYSTEM_APP, SecurityException::class.java)
)
.flatMap { param ->
mutableListOf(param).apply {
@@ -120,6 +126,13 @@ class PackageManagerComponentLabelIconOverrideTest {
}
}
+ @BeforeClass
+ @JvmStatic
+ fun disablePropertyInvalidatedCache() {
+ // Disable binder caches in this process.
+ PropertyInvalidatedCache.disableForTestMode()
+ }
+
data class Params(
val pkgName: String,
private val appType: AppType,
@@ -210,8 +223,10 @@ class PackageManagerComponentLabelIconOverrideTest {
fun verifyExpectedResult() {
if (params.componentName != null) {
val activityInfo = service.getActivityInfo(params.componentName, 0, userId)
- assertThat(activityInfo.nonLocalizedLabel).isEqualTo(params.expectedLabel)
- assertThat(activityInfo.icon).isEqualTo(params.expectedIcon)
+ if (activityInfo != null) {
+ assertThat(activityInfo.nonLocalizedLabel).isEqualTo(params.expectedLabel)
+ assertThat(activityInfo.icon).isEqualTo(params.expectedIcon)
+ }
}
}
@@ -294,34 +309,41 @@ class PackageManagerComponentLabelIconOverrideTest {
SHARED_PKG to makePkg(SHARED_PKG) { uid = Binder.getCallingUid() },
INVALID_PKG to makePkg(INVALID_PKG) { uid = Binder.getCallingUid() + 1 }
)
- val mockedPkgSettings = mapOf(
+ val mockedPkgSettings = mutableMapOf(
VALID_PKG to makePkgSetting(VALID_PKG),
SHARED_PKG to makePkgSetting(SHARED_PKG),
INVALID_PKG to makePkgSetting(INVALID_PKG)
)
- // Add pkgSetting under test so its attributes override the defaults added above
- .plus(params.pkgName to mockPkgSetting)
-
- val mockActivity: ParsedActivity = mock {
- whenever(this.packageName) { params.pkgName }
- whenever(this.nonLocalizedLabel) { DEFAULT_LABEL }
- whenever(this.icon) { DEFAULT_ICON }
- whenever(this.componentName) { params.componentName }
- whenever(this.name) { params.componentName?.className }
- whenever(this.isEnabled) { true }
- whenever(this.isDirectBootAware) { params.isSystem }
+
+ var mockActivity: ParsedActivity? = null
+ if (mockedPkgSettings.containsKey(params.pkgName)) {
+ // Add pkgSetting under test so its attributes override the defaults added above
+ mockedPkgSettings.put(params.pkgName, mockPkgSetting)
+
+ mockActivity = mock<ParsedActivity> {
+ whenever(this.packageName) { params.pkgName }
+ whenever(this.nonLocalizedLabel) { DEFAULT_LABEL }
+ whenever(this.icon) { DEFAULT_ICON }
+ whenever(this.componentName) { params.componentName }
+ whenever(this.name) { params.componentName?.className }
+ whenever(this.isEnabled) { true }
+ whenever(this.isDirectBootAware) { params.isSystem }
+ }
}
val mockSettings = Settings(mockedPkgSettings)
val mockComponentResolver: ComponentResolver = mockThrowOnUnmocked {
params.componentName?.let {
- whenever(this.componentExists(same(it))) { true }
+ whenever(this.componentExists(same(it))) { mockActivity != null }
whenever(this.getActivity(same(it))) { mockActivity }
}
}
val mockUserManagerService: UserManagerService = mockThrowOnUnmocked {
val matcher: (Int) -> Boolean = { it == userId || it == userIdDifferent }
whenever(this.exists(intThat(matcher))) { true }
+ }
+ val mockUserManagerInternal: UserManagerInternal = mockThrowOnUnmocked {
+ val matcher: (Int) -> Boolean = { it == userId || it == userIdDifferent }
whenever(this.isUserUnlockingOrUnlocked(intThat(matcher))) { true }
}
val mockActivityTaskManager: ActivityTaskManagerInternal = mockThrowOnUnmocked {
@@ -340,18 +362,19 @@ class PackageManagerComponentLabelIconOverrideTest {
}
}
val mockInjector: PackageManagerService.Injector = mock {
- whenever(this.lock) { Object() }
+ whenever(this.lock) { PackageManagerTracedLock() }
whenever(this.componentResolver) { mockComponentResolver }
whenever(this.userManagerService) { mockUserManagerService }
+ whenever(this.getUserManagerInternal()) { mockUserManagerInternal }
whenever(this.settings) { mockSettings }
whenever(this.getLocalService(ActivityTaskManagerInternal::class.java)) {
mockActivityTaskManager
}
whenever(this.appsFilter) { mockAppsFilter }
whenever(this.context) { mockContext }
+ whenever(this.getHandler()) { testHandler }
}
val testParams = PackageManagerService.TestParams().apply {
- this.handler = testHandler
this.pendingPackageBroadcasts = mockPendingBroadcasts
this.resolveComponentName = ComponentName("android", ".Test")
this.packages = ArrayMap<String, AndroidPackage>().apply { putAll(mockedPkgs) }
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 24e11af23798..ff7cd75dd7a1 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -45,6 +45,7 @@ android_test {
"service-permission.impl",
"service-blobstore",
"service-appsearch",
+ "androidx.test.core",
"androidx.test.runner",
"androidx.test.ext.truth",
"mockito-target-extended-minus-junit4",
diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java b/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
new file mode 100644
index 000000000000..da0b83ec819c
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
@@ -0,0 +1,235 @@
+/*
+ * 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.server.appsearch.stats;
+
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.appsearch.AppSearchConfig;
+import com.android.server.appsearch.external.localstorage.stats.CallStats;
+import com.android.server.testables.TestableDeviceConfig;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/**
+ * Tests covering the functionalities in {@link PlatformLogger} requiring overriding some flags
+ * in {@link DeviceConfig}.
+ *
+ * <p>To add tests NOT rely on overriding the configs, please add them in
+ * the tests for {@link PlatformLogger} in servicetests.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class PlatformLoggerTest {
+ private static final int TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 100;
+ private static final int TEST_DEFAULT_SAMPLING_INTERVAL = 10;
+ private static final String TEST_PACKAGE_NAME = "packageName";
+ private AppSearchConfig mAppSearchConfig;
+
+ @Rule
+ public final TestableDeviceConfig.TestableDeviceConfigRule
+ mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
+
+ @Before
+ public void setUp() throws Exception {
+ mAppSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR);
+ }
+
+ @Test
+ public void testCreateExtraStatsLocked_samplingIntervalNotSet_returnsDefault() {
+ PlatformLogger logger = new PlatformLogger(
+ ApplicationProvider.getApplicationContext(),
+ UserHandle.of(UserHandle.USER_NULL),
+ mAppSearchConfig);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
+ Long.toString(TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
+ Integer.toString(TEST_DEFAULT_SAMPLING_INTERVAL),
+ false);
+
+ // Make sure default sampling interval is used if there is no config set.
+ assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
+ CallStats.CALL_TYPE_UNKNOWN).mSamplingInterval).isEqualTo(
+ TEST_DEFAULT_SAMPLING_INTERVAL);
+ assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
+ CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo(
+ TEST_DEFAULT_SAMPLING_INTERVAL);
+ assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
+ CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo(
+ TEST_DEFAULT_SAMPLING_INTERVAL);
+ assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
+ CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
+ TEST_DEFAULT_SAMPLING_INTERVAL);
+ }
+
+
+ @Test
+ public void testCreateExtraStatsLocked_samplingIntervalSet_returnsConfigured() {
+ int putDocumentSamplingInterval = 1;
+ int batchCallSamplingInterval = 2;
+ PlatformLogger logger = new PlatformLogger(
+ ApplicationProvider.getApplicationContext(),
+ UserHandle.of(UserHandle.USER_NULL), mAppSearchConfig);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
+ Long.toString(TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
+ Integer.toString(TEST_DEFAULT_SAMPLING_INTERVAL),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS,
+ Integer.toString(putDocumentSamplingInterval),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS,
+ Integer.toString(batchCallSamplingInterval),
+ false);
+
+ // The default sampling interval should be used if no sampling interval is
+ // provided for certain call type.
+ assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
+ CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo(
+ TEST_DEFAULT_SAMPLING_INTERVAL);
+ assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
+ CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
+ TEST_DEFAULT_SAMPLING_INTERVAL);
+
+ // The configured sampling interval is used if sampling interval is available
+ // for certain call type.
+ assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
+ CallStats.CALL_TYPE_PUT_DOCUMENT).mSamplingInterval).isEqualTo(
+ putDocumentSamplingInterval);
+ assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
+ CallStats.CALL_TYPE_PUT_DOCUMENTS).mSamplingInterval).isEqualTo(
+ batchCallSamplingInterval);
+ assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
+ CallStats.CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH).mSamplingInterval).isEqualTo(
+ batchCallSamplingInterval);
+ }
+
+ @Test
+ public void testShouldLogForTypeLocked_trueWhenSampleIntervalIsOne() {
+ final String testPackageName = "packageName";
+ PlatformLogger logger = new PlatformLogger(
+ ApplicationProvider.getApplicationContext(),
+ UserHandle.of(UserHandle.USER_NULL),
+ mAppSearchConfig);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
+ Long.toString(1),
+ false);
+
+ // Sample should always be logged for the first time if sampling is disabled(value is one).
+ assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isTrue();
+ assertThat(logger.createExtraStatsLocked(testPackageName,
+ CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
+ }
+
+ @Test
+ public void testShouldLogForTypeLocked_falseWhenSampleIntervalIsNegative() {
+ final String testPackageName = "packageName";
+ PlatformLogger logger = new PlatformLogger(
+ ApplicationProvider.getApplicationContext(),
+ UserHandle.of(UserHandle.USER_NULL),
+ mAppSearchConfig);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
+ Long.toString(-1),
+ false);
+
+ // Makes sure sample will be excluded due to sampling if sample interval is negative.
+ assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isFalse();
+ // Skipped count should be 0 since it doesn't pass the sampling.
+ assertThat(logger.createExtraStatsLocked(testPackageName,
+ CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
+ }
+
+ @Test
+ public void testShouldLogForTypeLocked_falseWhenWithinCoolOffInterval() {
+ // Next sample won't be excluded due to sampling.
+ final int samplingInterval = 1;
+ // Next sample would guaranteed to be too close.
+ final int minTimeIntervalBetweenSamplesMillis = Integer.MAX_VALUE;
+ final String testPackageName = "packageName";
+ PlatformLogger logger = new PlatformLogger(
+ ApplicationProvider.getApplicationContext(),
+ UserHandle.of(UserHandle.USER_NULL),
+ mAppSearchConfig);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
+ Long.toString(samplingInterval),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
+ Long.toString(minTimeIntervalBetweenSamplesMillis),
+ false);
+ logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
+
+ // Makes sure sample will be excluded due to rate limiting if samples are too close.
+ assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isFalse();
+ assertThat(logger.createExtraStatsLocked(testPackageName,
+ CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(1);
+ }
+
+ @Test
+ public void testShouldLogForTypeLocked_trueWhenOutsideOfCoolOffInterval() {
+ // Next sample won't be excluded due to sampling.
+ final int samplingInterval = 1;
+ // Next sample would guaranteed to be included.
+ final int minTimeIntervalBetweenSamplesMillis = 0;
+ final String testPackageName = "packageName";
+ PlatformLogger logger = new PlatformLogger(
+ ApplicationProvider.getApplicationContext(),
+ UserHandle.of(UserHandle.USER_NULL),
+ mAppSearchConfig);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT,
+ Long.toString(samplingInterval),
+ false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+ AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
+ Long.toString(minTimeIntervalBetweenSamplesMillis),
+ false);
+ logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
+
+ // Makes sure sample will be logged if it is not too close to previous sample.
+ assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isTrue();
+ assertThat(logger.createExtraStatsLocked(testPackageName,
+ CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
index 7e1639e83ea0..7c275e13e24a 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
@@ -16,6 +16,8 @@
package com.android.server.appsearch.stats;
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.anyInt;
@@ -28,13 +30,12 @@ import android.annotation.NonNull;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArrayMap;
-import android.util.SparseIntArray;
import androidx.test.core.app.ApplicationProvider;
+import com.android.server.appsearch.AppSearchConfig;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import org.junit.Before;
@@ -48,11 +49,14 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
+/**
+ * Tests covering the functionalities in {@link PlatformLogger} NOT requiring overriding any flags
+ * in {@link android.provider.DeviceConfig}.
+ *
+ * <p>To add tests rely on overriding the flags, please add them in the
+ * tests for {@link PlatformLogger} in mockingservicestests.
+ */
public class PlatformLoggerTest {
- private static final int TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 100;
- private static final int TEST_DEFAULT_SAMPLING_INTERVAL = 10;
- private static final String TEST_PACKAGE_NAME = "packageName";
-
private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
private Context mContext;
@@ -73,66 +77,6 @@ public class PlatformLoggerTest {
}
@Test
- public void testCreateExtraStatsLocked_nullSamplingIntervalMap_returnsDefault() {
- PlatformLogger logger = new PlatformLogger(
- ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
- new PlatformLogger.Config(
- TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
- TEST_DEFAULT_SAMPLING_INTERVAL,
- /*samplingIntervals=*/ new SparseIntArray()));
-
- // Make sure default sampling interval is used if samplingMap is not provided.
- assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
- CallStats.CALL_TYPE_UNKNOWN).mSamplingInterval).isEqualTo(
- TEST_DEFAULT_SAMPLING_INTERVAL);
- assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
- CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo(
- TEST_DEFAULT_SAMPLING_INTERVAL);
- assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
- CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo(
- TEST_DEFAULT_SAMPLING_INTERVAL);
- assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
- CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
- TEST_DEFAULT_SAMPLING_INTERVAL);
- }
-
-
- @Test
- public void testCreateExtraStatsLocked_with_samplingIntervalMap_returnsConfigured() {
- int putDocumentSamplingInterval = 1;
- int querySamplingInterval = 2;
- final SparseIntArray samplingIntervals = new SparseIntArray();
- samplingIntervals.put(CallStats.CALL_TYPE_PUT_DOCUMENT, putDocumentSamplingInterval);
- samplingIntervals.put(CallStats.CALL_TYPE_SEARCH, querySamplingInterval);
- PlatformLogger logger = new PlatformLogger(
- ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
- new PlatformLogger.Config(
- TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
- TEST_DEFAULT_SAMPLING_INTERVAL,
- samplingIntervals));
-
- // The default sampling interval should be used if no sampling interval is
- // provided for certain call type.
- assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
- CallStats.CALL_TYPE_INITIALIZE).mSamplingInterval).isEqualTo(
- TEST_DEFAULT_SAMPLING_INTERVAL);
- assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
- CallStats.CALL_TYPE_FLUSH).mSamplingInterval).isEqualTo(
- TEST_DEFAULT_SAMPLING_INTERVAL);
-
- // The configured sampling interval is used if sampling interval is available
- // for certain call type.
- assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
- CallStats.CALL_TYPE_PUT_DOCUMENT).mSamplingInterval).isEqualTo(
- putDocumentSamplingInterval);
- assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
- CallStats.CALL_TYPE_SEARCH).mSamplingInterval).isEqualTo(
- querySamplingInterval);
- }
-
- @Test
public void testCalculateHashCode_MD5_int32_shortString()
throws NoSuchAlgorithmException, UnsupportedEncodingException {
final String str1 = "d1";
@@ -202,87 +146,6 @@ public class PlatformLoggerTest {
assertThat(PlatformLogger.calculateHashCodeMd5(/*str=*/ null)).isEqualTo(-1);
}
- @Test
- public void testShouldLogForTypeLocked_trueWhenSampleIntervalIsOne() {
- final int samplingInterval = 1;
- final String testPackageName = "packageName";
- PlatformLogger logger = new PlatformLogger(
- ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
- new PlatformLogger.Config(
- TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
- samplingInterval,
- /*samplingIntervals=*/ new SparseIntArray()));
-
- // Sample should always be logged for the first time if sampling is disabled(value is one).
- assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isTrue();
- assertThat(logger.createExtraStatsLocked(testPackageName,
- CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
- }
-
- @Test
- public void testShouldLogForTypeLocked_falseWhenSampleIntervalIsNegative() {
- final int samplingInterval = -1;
- final String testPackageName = "packageName";
- PlatformLogger logger = new PlatformLogger(
- ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
- new PlatformLogger.Config(
- TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
- samplingInterval,
- /*samplingIntervals=*/ new SparseIntArray()));
-
- // Makes sure sample will be excluded due to sampling if sample interval is negative.
- assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isFalse();
- // Skipped count should be 0 since it doesn't pass the sampling.
- assertThat(logger.createExtraStatsLocked(testPackageName,
- CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
- }
-
- @Test
- public void testShouldLogForTypeLocked_falseWhenWithinCoolOffInterval() {
- // Next sample won't be excluded due to sampling.
- final int samplingInterval = 1;
- // Next sample would guaranteed to be too close.
- final int minTimeIntervalBetweenSamplesMillis = Integer.MAX_VALUE;
- final String testPackageName = "packageName";
- PlatformLogger logger = new PlatformLogger(
- ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
- new PlatformLogger.Config(
- minTimeIntervalBetweenSamplesMillis,
- samplingInterval,
- /*samplingIntervals=*/ new SparseIntArray()));
- logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
-
- // Makes sure sample will be excluded due to rate limiting if samples are too close.
- assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isFalse();
- assertThat(logger.createExtraStatsLocked(testPackageName,
- CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(1);
- }
-
- @Test
- public void testShouldLogForTypeLocked_trueWhenOutsideOfCoolOffInterval() {
- // Next sample won't be excluded due to sampling.
- final int samplingInterval = 1;
- // Next sample would guaranteed to be included.
- final int minTimeIntervalBetweenSamplesMillis = 0;
- final String testPackageName = "packageName";
- PlatformLogger logger = new PlatformLogger(
- ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
- new PlatformLogger.Config(
- minTimeIntervalBetweenSamplesMillis,
- samplingInterval,
- /*samplingIntervals=*/ new SparseIntArray()));
- logger.setLastPushTimeMillisLocked(SystemClock.elapsedRealtime());
-
- // Makes sure sample will be logged if it is not too close to previous sample.
- assertThat(logger.shouldLogForTypeLocked(CallStats.CALL_TYPE_PUT_DOCUMENT)).isTrue();
- assertThat(logger.createExtraStatsLocked(testPackageName,
- CallStats.CALL_TYPE_PUT_DOCUMENT).mSkippedSampleCount).isEqualTo(0);
- }
-
/** Makes sure the caching works while getting the UID for calling package. */
@Test
public void testGetPackageUidAsUser() throws Exception {
@@ -291,10 +154,7 @@ public class PlatformLoggerTest {
PlatformLogger logger = new PlatformLogger(
mContext,
mContext.getUser(),
- new PlatformLogger.Config(
- TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
- TEST_DEFAULT_SAMPLING_INTERVAL,
- /*samplingIntervals=*/ new SparseIntArray()));
+ AppSearchConfig.create(DIRECT_EXECUTOR));
PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
when(mockPackageManager.getPackageUid(testPackageName, /*flags=*/0)).thenReturn(testUid);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 654d9fcf9210..fd41b9c19a2e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -15,6 +15,9 @@
*/
package com.android.server.devicepolicy;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.OP_ACTIVATE_VPN;
import static android.app.Notification.EXTRA_TEXT;
import static android.app.Notification.EXTRA_TITLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
@@ -7436,6 +7439,101 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertThrows(SecurityException.class, () -> dpm.setRecommendedGlobalProxy(admin1, null));
}
+ @Test
+ public void testSetAlwaysOnVpnPackage_clearsAdminVpn() throws Exception {
+ setDeviceOwner();
+
+ when(getServices().vpnManager
+ .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any()))
+ .thenReturn(true);
+
+ // Set VPN package to admin package.
+ dpm.setAlwaysOnVpnPackage(admin1, admin1.getPackageName(), false, null);
+
+ verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser(
+ UserHandle.USER_SYSTEM, admin1.getPackageName(), false, null);
+
+ // Clear VPN package.
+ dpm.setAlwaysOnVpnPackage(admin1, null, false, null);
+
+ // Change should be propagated to VpnManager
+ verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser(
+ UserHandle.USER_SYSTEM, null, false, null);
+ // The package should lose authorization to start VPN.
+ verify(getServices().appOpsManager).setMode(OP_ACTIVATE_VPN,
+ DpmMockContext.CALLER_SYSTEM_USER_UID, admin1.getPackageName(), MODE_DEFAULT);
+ }
+
+ @Test
+ public void testSetAlwaysOnVpnPackage_doesntKillUserVpn() throws Exception {
+ setDeviceOwner();
+
+ when(getServices().vpnManager
+ .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any()))
+ .thenReturn(true);
+
+ // this time it shouldn't go into VpnManager anymore.
+ dpm.setAlwaysOnVpnPackage(admin1, null, false, null);
+
+ verifyNoMoreInteractions(getServices().vpnManager);
+ verifyNoMoreInteractions(getServices().appOpsManager);
+ }
+
+ @Test
+ public void testDisallowConfigVpn_clearsUserVpn() throws Exception {
+ final String userVpnPackage = "org.some.vpn.servcie";
+ final int userVpnUid = 20374;
+
+ setDeviceOwner();
+
+ setupVpnAuthorization(userVpnPackage, userVpnUid);
+
+ simulateRestrictionAdded(UserManager.DISALLOW_CONFIG_VPN);
+
+ verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser(
+ UserHandle.USER_SYSTEM, null, false, null);
+ verify(getServices().appOpsManager).setMode(OP_ACTIVATE_VPN,
+ userVpnUid, userVpnPackage, MODE_DEFAULT);
+ }
+
+ @Test
+ public void testDisallowConfigVpn_doesntKillAdminVpn() throws Exception {
+ setDeviceOwner();
+
+ when(getServices().vpnManager
+ .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any()))
+ .thenReturn(true);
+
+ // Set VPN package to admin package.
+ dpm.setAlwaysOnVpnPackage(admin1, admin1.getPackageName(), false, null);
+ setupVpnAuthorization(admin1.getPackageName(), DpmMockContext.CALLER_SYSTEM_USER_UID);
+ clearInvocations(getServices().vpnManager);
+
+ simulateRestrictionAdded(UserManager.DISALLOW_CONFIG_VPN);
+
+ // Admin-set package should remain always-on and should retain its authorization.
+ verifyNoMoreInteractions(getServices().vpnManager);
+ verify(getServices().appOpsManager, never()).setMode(OP_ACTIVATE_VPN,
+ DpmMockContext.CALLER_SYSTEM_USER_UID, admin1.getPackageName(), MODE_DEFAULT);
+ }
+
+ private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) {
+ final AppOpsManager.PackageOps vpnOp = new AppOpsManager.PackageOps(userVpnPackage,
+ userVpnUid, List.of(new AppOpsManager.OpEntry(
+ OP_ACTIVATE_VPN, MODE_ALLOWED, Collections.emptyMap())));
+ when(getServices().appOpsManager.getPackagesForOps(any(int[].class)))
+ .thenReturn(List.of(vpnOp));
+ }
+
+ private void simulateRestrictionAdded(String restriction) {
+ RestrictionsListener listener = new RestrictionsListener(
+ mServiceContext, getServices().userManagerInternal, dpms);
+
+ final Bundle newRestrictions = new Bundle();
+ newRestrictions.putBoolean(restriction, true);
+ listener.onUserRestrictionsChanged(UserHandle.USER_SYSTEM, newRestrictions, new Bundle());
+ }
+
private void setUserUnlocked(int userHandle, boolean unlocked) {
when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 2e004683acdb..d10419d4bfc5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -230,6 +230,8 @@ public class DpmMockContext extends MockContext {
return mMockSystemServices.appOpsManager;
case Context.CROSS_PROFILE_APPS_SERVICE:
return mMockSystemServices.crossProfileApps;
+ case Context.VPN_MANAGEMENT_SERVICE:
+ return mMockSystemServices.vpnManager;
}
throw new UnsupportedOperationException();
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 9cc057252a4c..8a2919d55216 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -50,6 +50,7 @@ import android.media.IAudioService;
import android.net.ConnectivityManager;
import android.net.IIpConnectivityMetrics;
import android.net.Uri;
+import android.net.VpnManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.PowerManager;
@@ -123,6 +124,7 @@ public class MockSystemServices {
public final PersistentDataBlockManagerInternal persistentDataBlockManagerInternal;
public final AppOpsManager appOpsManager;
public final UsbManager usbManager;
+ public final VpnManager vpnManager;
/** Note this is a partial mock, not a real mock. */
public final PackageManager packageManager;
public final BuildMock buildMock = new BuildMock();
@@ -169,6 +171,7 @@ public class MockSystemServices {
persistentDataBlockManagerInternal = mock(PersistentDataBlockManagerInternal.class);
appOpsManager = mock(AppOpsManager.class);
usbManager = mock(UsbManager.class);
+ vpnManager = mock(VpnManager.class);
// Package manager is huge, so we use a partial mock instead.
packageManager = spy(realContext.getPackageManager());
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index c50648573d52..2a4896a7b041 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -134,6 +134,8 @@ public final class DataManagerTest {
private static final String NOTIFICATION_CHANNEL_ID = "test : sc";
private static final String PARENT_NOTIFICATION_CHANNEL_ID = "test";
private static final long MILLIS_PER_MINUTE = 1000L * 60L;
+ private static final String GENERIC_KEY = "key";
+ private static final String CUSTOM_KEY = "custom";
@Mock
private Context mContext;
@@ -158,7 +160,11 @@ public final class DataManagerTest {
@Mock
private JobScheduler mJobScheduler;
@Mock
- private StatusBarNotification mStatusBarNotification;
+ private StatusBarNotification mGenericSbn;
+ @Mock
+ private StatusBarNotification mConvoSbn;
+ @Mock
+ private NotificationListenerService.RankingMap mRankingMap;
@Mock
private Notification mNotification;
@Mock
@@ -202,8 +208,6 @@ public final class DataManagerTest {
mParentNotificationChannel = new NotificationChannel(
PARENT_NOTIFICATION_CHANNEL_ID, "test channel",
NotificationManager.IMPORTANCE_DEFAULT);
- when(mNotificationManagerInternal.getNotificationChannel(anyString(), anyInt(),
- anyString())).thenReturn(mParentNotificationChannel);
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
@@ -246,16 +250,26 @@ public final class DataManagerTest {
when(mPackageManager.getPackageUidAsUser(TEST_PKG_NAME, USER_ID_PRIMARY))
.thenReturn(TEST_PKG_UID);
- when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
- when(mStatusBarNotification.getPackageName()).thenReturn(TEST_PKG_NAME);
- when(mStatusBarNotification.getUser()).thenReturn(UserHandle.of(USER_ID_PRIMARY));
- when(mStatusBarNotification.getPostTime()).thenReturn(System.currentTimeMillis());
- when(mNotification.getShortcutId()).thenReturn(TEST_SHORTCUT_ID);
- when(mNotification.getChannelId()).thenReturn(PARENT_NOTIFICATION_CHANNEL_ID);
-
mNotificationChannel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID, "test channel", NotificationManager.IMPORTANCE_DEFAULT);
- mNotificationChannel.setConversationId("test", TEST_SHORTCUT_ID);
+ mNotificationChannel.setConversationId(PARENT_NOTIFICATION_CHANNEL_ID, TEST_SHORTCUT_ID);
+ when(mNotificationManagerInternal.getNotificationChannel(anyString(), anyInt(),
+ eq(mNotificationChannel.getId()))).thenReturn(mNotificationChannel);
+ when(mNotificationManagerInternal.getNotificationChannel(anyString(), anyInt(),
+ eq(mParentNotificationChannel.getId()))).thenReturn(mParentNotificationChannel);
+
+ when(mGenericSbn.getKey()).thenReturn(GENERIC_KEY);
+ when(mGenericSbn.getNotification()).thenReturn(mNotification);
+ when(mGenericSbn.getPackageName()).thenReturn(TEST_PKG_NAME);
+ when(mGenericSbn.getUser()).thenReturn(UserHandle.of(USER_ID_PRIMARY));
+ when(mGenericSbn.getPostTime()).thenReturn(System.currentTimeMillis());
+ when(mConvoSbn.getKey()).thenReturn(CUSTOM_KEY);
+ when(mConvoSbn.getNotification()).thenReturn(mNotification);
+ when(mConvoSbn.getPackageName()).thenReturn(TEST_PKG_NAME);
+ when(mConvoSbn.getUser()).thenReturn(UserHandle.of(USER_ID_PRIMARY));
+ when(mConvoSbn.getPostTime()).thenReturn(System.currentTimeMillis());
+
+ when(mNotification.getShortcutId()).thenReturn(TEST_SHORTCUT_ID);
mCancellationSignal = new CancellationSignal();
@@ -449,10 +463,7 @@ public final class DataManagerTest {
buildPerson());
mDataManager.addOrUpdateConversationInfo(shortcut);
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
-
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
List<Range<Long>> activeNotificationOpenTimeSlots = getActiveSlotsForTestShortcut(
Event.NOTIFICATION_EVENT_TYPES);
@@ -471,7 +482,7 @@ public final class DataManagerTest {
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ listenerService.onNotificationRemoved(mGenericSbn, null,
NotificationListenerService.REASON_CLICK);
List<Range<Long>> activeNotificationOpenTimeSlots = getActiveSlotsForTestShortcut(
@@ -495,20 +506,20 @@ public final class DataManagerTest {
shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
when(mNotification.getShortcutId()).thenReturn(shortcutId);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
}
// Post another notification for the last conversation.
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
// Removing one of the two notifications does not un-cache the shortcut.
- listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ listenerService.onNotificationRemoved(mGenericSbn, null,
NotificationListenerService.REASON_CANCEL);
verify(mShortcutServiceInternal, never()).uncacheShortcuts(
anyInt(), any(), anyString(), any(), anyInt(), anyInt());
// Removing the second notification un-caches the shortcut.
- listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ listenerService.onNotificationRemoved(mGenericSbn, null,
NotificationListenerService.REASON_CANCEL_ALL);
verify(mShortcutServiceInternal).uncacheShortcuts(
anyInt(), any(), eq(TEST_PKG_NAME), anyList(), eq(USER_ID_PRIMARY),
@@ -526,7 +537,7 @@ public final class DataManagerTest {
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
@@ -626,19 +637,13 @@ public final class DataManagerTest {
buildPerson());
mDataManager.addOrUpdateConversationInfo(shortcut);
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
-
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendConvoNotification();
shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
TEST_SHORTCUT_ID)).isNotNull();
- listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
- mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
-
ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
TEST_SHORTCUT_ID);
assertThat(result).isNotNull();
@@ -661,9 +666,7 @@ public final class DataManagerTest {
assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
TEST_SHORTCUT_ID + "1")).isNull();
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendConvoNotification();
ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
@@ -673,15 +676,51 @@ public final class DataManagerTest {
assertEquals(shortcut.getId(), result.getShortcutInfo().getId());
assertEquals(1, result.getShortcutInfo().getPersons().length);
assertEquals(CONTACT_URI, result.getShortcutInfo().getPersons()[0].getUri());
+ assertEquals(mNotificationChannel.getId(), result.getNotificationChannel().getId());
assertEquals(mParentNotificationChannel.getId(),
- result.getParentNotificationChannel().getId());
- assertEquals(mStatusBarNotification.getPostTime(), result.getLastEventTimestamp());
+ result.getNotificationChannel().getParentChannelId());
+ assertEquals(mConvoSbn.getPostTime(), result.getLastEventTimestamp());
assertTrue(result.hasActiveNotifications());
assertFalse(result.hasBirthdayToday());
assertThat(result.getStatuses()).containsExactly(cs);
}
@Test
+ public void testOnNotificationChannelModified() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID)).isNull();
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_PINNED);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ sendConvoNotification();
+
+ ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID);
+ assertFalse(result.getNotificationChannel().canBubble());
+
+ NotificationChannel updated = new NotificationChannel(mNotificationChannel.getId(),
+ mNotificationChannel.getDescription(), mNotificationChannel.getImportance());
+ updated.setConversationId(mNotificationChannel.getParentChannelId(),
+ mNotificationChannel.getConversationId());
+ updated.setAllowBubbles(true);
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+ updated, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
+
+ ConversationInfo ci = mDataManager.getConversationInfo(TEST_PKG_NAME, USER_ID_PRIMARY,
+ TEST_SHORTCUT_ID);
+ assertThat(ci).isNotNull();
+ assertEquals(mNotificationChannel.getId(), ci.getNotificationChannelId());
+ assertEquals(mParentNotificationChannel.getId(), ci.getParentNotificationChannelId());
+ assertTrue(ci.isBubbled());
+ }
+
+ @Test
public void testGetConversation_demoted() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
@@ -713,11 +752,8 @@ public final class DataManagerTest {
shortcut.setCached(ShortcutInfo.FLAG_PINNED);
mDataManager.addOrUpdateConversationInfo(shortcut);
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
- ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
- TEST_SHORTCUT_ID);
+ sendGenericNotification();
+ mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID);
verify(mShortcutServiceInternal).getShortcuts(
anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
@@ -1085,7 +1121,7 @@ public final class DataManagerTest {
shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
when(mNotification.getShortcutId()).thenReturn(shortcutId);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
}
mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
@@ -1107,9 +1143,9 @@ public final class DataManagerTest {
shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
when(mNotification.getShortcutId()).thenReturn(shortcutId);
- when(mStatusBarNotification.getPostTime()).thenReturn(100L + i);
- listenerService.onNotificationPosted(mStatusBarNotification);
- listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ when(mGenericSbn.getPostTime()).thenReturn(100L + i);
+ sendGenericNotification();
+ listenerService.onNotificationRemoved(mGenericSbn, null,
NotificationListenerService.REASON_CANCEL);
}
@@ -1162,9 +1198,7 @@ public final class DataManagerTest {
shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
assertEquals(1, result.size());
@@ -1172,8 +1206,9 @@ public final class DataManagerTest {
assertEquals(1, result.get(0).getShortcutInfo().getPersons().length);
assertEquals(CONTACT_URI, result.get(0).getShortcutInfo().getPersons()[0].getUri());
assertEquals(mParentNotificationChannel.getId(),
- result.get(0).getParentNotificationChannel().getId());
- assertEquals(mStatusBarNotification.getPostTime(), result.get(0).getLastEventTimestamp());
+ result.get(0).getNotificationChannel().getId());
+ assertEquals(null, result.get(0).getNotificationChannel().getParentChannelId());
+ assertEquals(mGenericSbn.getPostTime(), result.get(0).getLastEventTimestamp());
assertTrue(result.get(0).hasActiveNotifications());
}
@@ -1186,11 +1221,9 @@ public final class DataManagerTest {
shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
- List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
+ mDataManager.getRecentConversations(USER_ID_PRIMARY);
verify(mShortcutServiceInternal).getShortcuts(
anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
@@ -1211,8 +1244,8 @@ public final class DataManagerTest {
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
when(mNotification.getShortcutId()).thenReturn(TEST_SHORTCUT_ID);
- listenerService.onNotificationPosted(mStatusBarNotification);
- listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ sendGenericNotification();
+ listenerService.onNotificationRemoved(mGenericSbn, null,
NotificationListenerService.REASON_CLICK);
mDataManager.pruneOldRecentConversations(USER_ID_PRIMARY,
@@ -1231,11 +1264,9 @@ public final class DataManagerTest {
buildPerson());
mDataManager.addOrUpdateConversationInfo(shortcut);
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
- assertEquals(mStatusBarNotification.getPostTime(),
+ assertEquals(mGenericSbn.getPostTime(),
mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID));
assertEquals(0L,
mDataManager.getLastInteraction("not_test_pkg", USER_ID_PRIMARY, TEST_SHORTCUT_ID));
@@ -1375,9 +1406,7 @@ public final class DataManagerTest {
TEST_SHORTCUT_ID, buildPerson());
mDataManager.addOrUpdateConversationInfo(shortcut);
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
assertTrue(result.isEmpty());
@@ -1395,7 +1424,7 @@ public final class DataManagerTest {
// Post a notification and customize the notification settings.
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
@@ -1414,7 +1443,7 @@ public final class DataManagerTest {
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
// posting updates the last interaction time, so delay before deletion
try {
Thread.sleep(500);
@@ -1422,7 +1451,7 @@ public final class DataManagerTest {
e.printStackTrace();
}
long approxDeletionTime = System.currentTimeMillis();
- listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ listenerService.onNotificationRemoved(mGenericSbn, null,
NotificationListenerService.REASON_CANCEL);
ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
@@ -1442,8 +1471,8 @@ public final class DataManagerTest {
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- listenerService.onNotificationPosted(mStatusBarNotification);
- listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ sendGenericNotification();
+ listenerService.onNotificationRemoved(mGenericSbn, null,
NotificationListenerService.REASON_CANCEL);
mDataManager.removeRecentConversation(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
USER_ID_PRIMARY);
@@ -1472,14 +1501,14 @@ public final class DataManagerTest {
// Post a notification and then dismiss it for conversation #1.
when(mNotification.getShortcutId()).thenReturn("1");
- listenerService.onNotificationPosted(mStatusBarNotification);
- listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ sendGenericNotification();
+ listenerService.onNotificationRemoved(mGenericSbn, null,
NotificationListenerService.REASON_CANCEL);
// Post a notification for conversation #2, but don't dismiss it. Its shortcut won't be
// uncached when removeAllRecentConversations() is called.
when(mNotification.getShortcutId()).thenReturn("2");
- listenerService.onNotificationPosted(mStatusBarNotification);
+ sendGenericNotification();
mDataManager.removeAllRecentConversations(USER_ID_PRIMARY);
@@ -1562,6 +1591,58 @@ public final class DataManagerTest {
return (queryFlags & flag) != 0;
}
+ // "Sends" a notification to a non-customized notification channel - the notification channel
+ // is something generic like "messages" and the notification has a shortcut id
+ private void sendGenericNotification() {
+ when(mNotification.getChannelId()).thenReturn(PARENT_NOTIFICATION_CHANNEL_ID);
+ doAnswer(invocationOnMock -> {
+ NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking)
+ invocationOnMock.getArguments()[1];
+ ranking.populate(
+ (String) invocationOnMock.getArguments()[0],
+ 0,
+ false,
+ 0,
+ 0,
+ mParentNotificationChannel.getImportance(),
+ null, null,
+ mParentNotificationChannel, null, null, true, 0, false, -1, false, null, null,
+ false, false, false, null, 0, false);
+ return true;
+ }).when(mRankingMap).getRanking(eq(GENERIC_KEY),
+ any(NotificationListenerService.Ranking.class));
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mGenericSbn, mRankingMap);
+ }
+
+ // "Sends" a notification to a customized notification channel - the notification channel
+ // is specific to a person, and the channel has a convo id matching the notification's shortcut
+ // and the channel has a parent channel id
+ private void sendConvoNotification() {
+ when(mNotification.getChannelId()).thenReturn(NOTIFICATION_CHANNEL_ID);
+ doAnswer(invocationOnMock -> {
+ NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking)
+ invocationOnMock.getArguments()[1];
+ ranking.populate(
+ (String) invocationOnMock.getArguments()[0],
+ 0,
+ false,
+ 0,
+ 0,
+ mNotificationChannel.getImportance(),
+ null, null,
+ mNotificationChannel, null, null, true, 0, false, -1, false, null, null, false,
+ false, false, null, 0, false);
+ return true;
+ }).when(mRankingMap).getRanking(eq(CUSTOM_KEY),
+ any(NotificationListenerService.Ranking.class));
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mConvoSbn, mRankingMap);
+ }
+
private class TestContactsQueryHelper extends ContactsQueryHelper {
private Uri mContactUri;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index b3a07454c1a0..4c31ee2ae5fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -53,12 +53,12 @@ public class TestIWindow extends IWindow.Stub {
}
@Override
- public void insetsChanged(InsetsState insetsState) throws RemoteException {
+ public void insetsChanged(InsetsState insetsState, boolean willMove, boolean willResize) {
}
@Override
- public void insetsControlChanged(InsetsState insetsState, InsetsSourceControl[] activeControls)
- throws RemoteException {
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls, boolean willMove, boolean willResize) {
}
@Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 31825013604d..bac703121c10 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -34,6 +34,7 @@ import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.MediaRecorder;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IRemoteCallback;
@@ -48,6 +49,7 @@ import android.service.voice.HotwordRejectedResult;
import android.service.voice.IDspHotwordDetectionCallback;
import android.service.voice.IHotwordDetectionService;
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
+import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
import android.util.Pair;
import android.util.Slog;
import android.view.contentcapture.IContentCaptureManager;
@@ -56,6 +58,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
+import com.android.server.LocalServices;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.io.Closeable;
import java.io.IOException;
@@ -94,20 +98,24 @@ final class HotwordDetectionConnection {
private final AtomicBoolean mUpdateStateFinish = new AtomicBoolean(false);
final Object mLock;
+ final int mVoiceInteractionServiceUid;
final ComponentName mDetectionComponentName;
final int mUser;
final Context mContext;
final @NonNull ServiceConnector<IHotwordDetectionService> mRemoteHotwordDetectionService;
boolean mBound;
+ volatile HotwordDetectionServiceIdentity mIdentity;
@GuardedBy("mLock")
private ParcelFileDescriptor mCurrentAudioSink;
- HotwordDetectionConnection(Object lock, Context context, ComponentName serviceName,
- int userId, boolean bindInstantServiceAllowed, @Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) {
+ HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
+ ComponentName serviceName, int userId, boolean bindInstantServiceAllowed,
+ @Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory,
+ IHotwordRecognitionStatusCallback callback) {
mLock = lock;
mContext = context;
+ mVoiceInteractionServiceUid = voiceInteractionServiceUid;
mDetectionComponentName = serviceName;
mUser = userId;
final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE);
@@ -164,7 +172,15 @@ final class HotwordDetectionConnection {
public void sendResult(Bundle bundle) throws RemoteException {
if (DEBUG) {
Slog.d(TAG, "updateState finish");
+ Slog.d(TAG, "updating hotword UID " + Binder.getCallingUid());
}
+ // TODO: Do this earlier than this callback and have the provider point to the
+ // current state stored in VoiceInteractionManagerServiceImpl.
+ final int uid = Binder.getCallingUid();
+ LocalServices.getService(PermissionManagerServiceInternal.class)
+ .setHotwordDetectionServiceProvider(() -> uid);
+ mIdentity =
+ new HotwordDetectionServiceIdentity(uid, mVoiceInteractionServiceUid);
future.complete(null);
try {
if (mUpdateStateFinish.getAndSet(true)) {
@@ -235,6 +251,9 @@ final class HotwordDetectionConnection {
if (mBound) {
mRemoteHotwordDetectionService.unbind();
mBound = false;
+ LocalServices.getService(PermissionManagerServiceInternal.class)
+ .setHotwordDetectionServiceProvider(null);
+ mIdentity = null;
}
}
@@ -329,7 +348,7 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "onDetected");
}
- externalCallback.onKeyphraseDetected(recognitionEvent);
+ externalCallback.onKeyphraseDetected(recognitionEvent, result);
}
@Override
@@ -362,8 +381,7 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "onDetected");
}
- // TODO: Propagate the HotwordDetectedResult.
- externalCallback.onKeyphraseDetected(recognitionEvent);
+ externalCallback.onKeyphraseDetected(recognitionEvent, result);
}
@Override
@@ -407,7 +425,7 @@ final class HotwordDetectionConnection {
mHotwordDetectionConnection.detectFromDspSource(
recognitionEvent, mExternalCallback);
} else {
- mExternalCallback.onKeyphraseDetected(recognitionEvent);
+ mExternalCallback.onKeyphraseDetected(recognitionEvent, null);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index f3d80b13f290..a14912e5593d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -251,6 +251,26 @@ public class VoiceInteractionManagerService extends SystemService {
return TextUtils.equals(packageName, session.mSessionComponentName.getPackageName());
}
+
+ @Override
+ public HotwordDetectionServiceIdentity getHotwordDetectionServiceIdentity() {
+ // IMPORTANT: This is called when performing permission checks; do not lock!
+
+ // TODO: Have AppOpsPolicy register a listener instead of calling in here everytime.
+ // Then also remove the `volatile`s that were added with this method.
+
+ VoiceInteractionManagerServiceImpl impl =
+ VoiceInteractionManagerService.this.mServiceStub.mImpl;
+ if (impl == null) {
+ return null;
+ }
+ HotwordDetectionConnection hotwordDetectionConnection =
+ impl.mHotwordDetectionConnection;
+ if (hotwordDetectionConnection == null) {
+ return null;
+ }
+ return hotwordDetectionConnection.mIdentity;
+ }
}
// implementation entry point and binder service
@@ -258,7 +278,7 @@ public class VoiceInteractionManagerService extends SystemService {
class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
- VoiceInteractionManagerServiceImpl mImpl;
+ volatile VoiceInteractionManagerServiceImpl mImpl;
private boolean mSafeMode;
private int mCurUser;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 2206b0a61b9e..ca30bc51e046 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -98,7 +98,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
final ComponentName mHotwordDetectionComponentName;
boolean mBound = false;
IVoiceInteractionService mService;
- HotwordDetectionConnection mHotwordDetectionConnection;
+ volatile HotwordDetectionConnection mHotwordDetectionConnection;
VoiceInteractionSessionConnection mActiveSession;
int mDisabledShowContext;
@@ -447,8 +447,8 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
if (mHotwordDetectionConnection == null) {
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
- mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false,
- options, sharedMemory, callback);
+ mInfo.getServiceInfo().applicationInfo.uid, mHotwordDetectionComponentName,
+ mUser, /* bindInstantServiceAllowed= */ false, options, sharedMemory, callback);
} else {
mHotwordDetectionConnection.updateStateLocked(options, sharedMemory);
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
index 029e302d0382..15568ac72227 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
@@ -34,13 +34,14 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ProgressBar;
+import android.widget.TextView;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
import java.util.Random;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
public class PictureCaptureDemo extends Activity {
@Override
@@ -77,6 +78,12 @@ public class PictureCaptureDemo extends Activity {
iv2.setImageBitmap(Bitmap.createBitmap(picture, 100, 100, Bitmap.Config.HARDWARE));
inner.addView(iv2, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+ TextView hello = new TextView(this);
+ hello.setText("I'm on a layer!");
+ hello.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ inner.addView(hello,
+ new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+
layout.addView(inner,
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
// For testing with a functor in the tree
@@ -84,11 +91,13 @@ public class PictureCaptureDemo extends Activity {
wv.setWebViewClient(new WebViewClient());
wv.setWebChromeClient(new WebChromeClient());
wv.loadUrl("https://google.com");
- layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 400));
+ LayoutParams wvParams = new LayoutParams(LayoutParams.MATCH_PARENT, 400);
+ wvParams.bottomMargin = 50;
+ layout.addView(wv, wvParams);
SurfaceView mySurfaceView = new SurfaceView(this);
layout.addView(mySurfaceView,
- new LayoutParams(LayoutParams.MATCH_PARENT, 600));
+ new LayoutParams(LayoutParams.MATCH_PARENT, 600, 1f));
setContentView(layout);
@@ -98,22 +107,29 @@ public class PictureCaptureDemo extends Activity {
@Override
public void surfaceCreated(SurfaceHolder holder) {
final Random rand = new Random();
+ OutputStream renderingStream = new ByteArrayOutputStream() {
+ @Override
+ public void flush() throws IOException {
+ Picture picture = Picture.createFromStream(
+ new ByteArrayInputStream(buf, 0, count));
+ Canvas canvas = holder.lockCanvas();
+ if (canvas != null && picture != null) {
+ canvas.drawPicture(picture);
+ holder.unlockCanvasAndPost(canvas);
+ }
+ reset();
+ }
+ };
+
mStopCapture = ViewDebug.startRenderingCommandsCapture(mySurfaceView,
- mCaptureThread, (picture) -> {
+ Executors.newSingleThreadExecutor(), () -> {
if (rand.nextInt(20) == 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
- Canvas canvas = holder.lockCanvas();
- if (canvas == null) {
- return false;
- }
- canvas.drawPicture(picture);
- holder.unlockCanvasAndPost(canvas);
- picture.close();
- return true;
+ return renderingStream;
});
}
@@ -134,20 +150,4 @@ public class PictureCaptureDemo extends Activity {
}
});
}
-
- ExecutorService mCaptureThread = Executors.newSingleThreadExecutor();
- ExecutorService mExecutor = Executors.newSingleThreadExecutor();
-
- Picture deepCopy(Picture src) {
- try {
- PipedInputStream inputStream = new PipedInputStream();
- PipedOutputStream outputStream = new PipedOutputStream(inputStream);
- Future<Picture> future = mExecutor.submit(() -> Picture.createFromStream(inputStream));
- src.writeToStream(outputStream);
- outputStream.close();
- return future.get();
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
}