summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java22
-rw-r--r--apex/jobscheduler/service/aconfig/job.aconfig12
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java6
-rw-r--r--cmds/svc/src/com/android/commands/svc/OWNERS2
-rw-r--r--core/api/current.txt125
-rw-r--r--core/api/system-current.txt18
-rw-r--r--core/api/test-current.txt40
-rw-r--r--core/java/android/app/Activity.java18
-rw-r--r--core/java/android/app/ActivityThread.java2
-rw-r--r--core/java/android/app/ApplicationStartInfo.java89
-rw-r--r--core/java/android/app/AutomaticZenRule.java134
-rw-r--r--core/java/android/app/INotificationManager.aidl3
-rw-r--r--core/java/android/app/Notification.java19
-rw-r--r--core/java/android/app/NotificationManager.java70
-rw-r--r--core/java/android/app/UiAutomation.java29
-rw-r--r--core/java/android/app/UiModeManager.java6
-rw-r--r--core/java/android/app/backup/BackupRestoreEventLogger.java17
-rw-r--r--core/java/android/app/contextualsearch/ContextualSearchManager.java121
-rw-r--r--core/java/android/app/contextualsearch/IContextualSearchManager.aidl7
-rw-r--r--core/java/android/app/contextualsearch/flags.aconfig8
-rw-r--r--core/java/android/app/jank/JankDataProcessor.java113
-rw-r--r--core/java/android/app/jank/JankTracker.java136
-rw-r--r--core/java/android/app/notification.aconfig20
-rw-r--r--core/java/android/app/supervision/ISupervisionManager.aidl3
-rw-r--r--core/java/android/app/supervision/SupervisionManager.java71
-rw-r--r--core/java/android/app/supervision/flags.aconfig8
-rw-r--r--core/java/android/appwidget/flags.aconfig10
-rw-r--r--core/java/android/companion/virtual/flags/flags.aconfig10
-rw-r--r--core/java/android/content/AttributionSource.java9
-rw-r--r--core/java/android/content/Context.java6
-rw-r--r--core/java/android/content/Intent.java2
-rw-r--r--core/java/android/content/pm/multiuser.aconfig7
-rw-r--r--core/java/android/content/res/ApkAssets.java56
-rw-r--r--core/java/android/content/res/ResourceTimer.java56
-rw-r--r--core/java/android/content/res/XmlBlock.java32
-rw-r--r--core/java/android/hardware/contexthub/HubEndpointSession.java27
-rw-r--r--core/java/android/hardware/display/ColorDisplayManager.java2
-rw-r--r--core/java/android/hardware/display/DisplayManager.java15
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java23
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java4
-rw-r--r--core/java/android/hardware/input/InputSettings.java4
-rw-r--r--core/java/android/media/Image.java (renamed from media/java/android/media/Image.java)0
-rw-r--r--core/java/android/media/ImageReader.java (renamed from media/java/android/media/ImageReader.java)0
-rw-r--r--core/java/android/media/ImageUtils.java (renamed from media/java/android/media/ImageUtils.java)0
-rw-r--r--core/java/android/media/ImageWriter.java (renamed from media/java/android/media/ImageWriter.java)0
-rw-r--r--core/java/android/media/PublicFormatUtils.java (renamed from media/java/android/media/PublicFormatUtils.java)0
-rw-r--r--core/java/android/os/UserManager.java11
-rw-r--r--core/java/android/os/vibrator/VibratorFrequencyProfile.java22
-rw-r--r--core/java/android/permission/flags.aconfig7
-rw-r--r--core/java/android/provider/Settings.java12
-rw-r--r--core/java/android/security/FileIntegrityManager.java8
-rw-r--r--core/java/android/security/IFileIntegrityService.aidl2
-rw-r--r--core/java/android/security/flags.aconfig10
-rw-r--r--core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java8
-rw-r--r--core/java/android/service/notification/Condition.java52
-rw-r--r--core/java/android/service/notification/SystemZenRules.java3
-rw-r--r--core/java/android/service/notification/ZenAdapters.java8
-rw-r--r--core/java/android/service/notification/ZenDeviceEffects.java5
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java537
-rw-r--r--core/java/android/service/notification/ZenModeDiff.java93
-rw-r--r--core/java/android/service/notification/ZenPolicy.java118
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java13
-rw-r--r--core/java/android/text/Layout.java8
-rw-r--r--core/java/android/view/Display.java1
-rw-r--r--core/java/android/view/DisplayInfo.java27
-rw-r--r--core/java/android/view/NotificationHeaderView.java19
-rw-r--r--core/java/android/view/ViewRootImpl.java36
-rw-r--r--core/java/android/view/WindowManager.java10
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java21
-rw-r--r--core/java/android/view/flags/refresh_rate_flags.aconfig7
-rw-r--r--core/java/android/widget/RemoteViews.java16
-rw-r--r--core/java/android/window/DesktopModeFlags.java3
-rw-r--r--core/java/android/window/TaskFragmentOperation.java88
-rw-r--r--core/java/android/window/TransitionInfo.java4
-rw-r--r--core/java/android/window/flags/lse_desktop_experience.aconfig37
-rw-r--r--core/java/com/android/internal/app/OWNERS3
-rw-r--r--core/java/com/android/internal/jank/Cuj.java2
-rw-r--r--core/java/com/android/internal/pm/pkg/component/AconfigFlags.java15
-rw-r--r--core/java/com/android/internal/protolog/IProtoLogConfigurationService.aidl12
-rw-r--r--core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java16
-rw-r--r--core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java7
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java74
-rw-r--r--core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java2
-rw-r--r--core/java/com/android/internal/security/TEST_MAPPING4
-rw-r--r--core/java/com/android/internal/security/VerityUtils.java3
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java38
-rw-r--r--core/java/com/android/internal/widget/NotificationProgressBar.java7
-rw-r--r--core/java/com/android/internal/widget/remotecompose/OWNERS1
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java35
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/Operations.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/PaintContext.java7
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java41
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java36
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java8
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java119
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java16
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java27
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/Header.java365
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java28
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java12
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java34
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java9
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java13
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java13
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java13
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java17
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java175
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java20
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java10
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java34
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java18
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DrawContentOperation.java125
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java207
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java34
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/serialize/SerializeTags.java1
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java11
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java52
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java7
-rw-r--r--core/jni/Android.bp36
-rw-r--r--core/jni/AndroidRuntime.cpp6
-rw-r--r--core/jni/android_content_res_ApkAssets.cpp108
-rw-r--r--core/jni/android_media_AudioRecord.cpp2
-rw-r--r--core/jni/android_media_AudioSystem.cpp12
-rw-r--r--core/jni/android_media_AudioTrack.cpp2
-rw-r--r--core/jni/android_media_ImageReader.cpp (renamed from media/jni/android_media_ImageReader.cpp)1
-rw-r--r--core/jni/android_media_ImageWriter.cpp (renamed from media/jni/android_media_ImageWriter.cpp)1
-rw-r--r--core/jni/android_media_PublicFormatUtils.cpp (renamed from media/jni/android_media_PublicFormatUtils.cpp)0
-rw-r--r--core/jni/android_media_Utils.cpp (renamed from media/jni/android_media_Utils.cpp)0
-rw-r--r--core/jni/android_media_Utils.h (renamed from media/jni/android_media_Utils.h)0
-rw-r--r--core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp18
-rw-r--r--core/proto/android/nfc/OWNERS2
-rw-r--r--core/res/Android.bp1
-rw-r--r--core/res/AndroidManifest.xml186
-rw-r--r--core/res/res/drawable-w192dp/loader_horizontal_watch.xml97
-rw-r--r--core/res/res/drawable-w204dp/loader_horizontal_watch.xml104
-rw-r--r--core/res/res/drawable-w216dp/loader_horizontal_watch.xml105
-rw-r--r--core/res/res/drawable-w228dp/loader_horizontal_watch.xml103
-rw-r--r--core/res/res/drawable-w240dp/loader_horizontal_watch.xml104
-rw-r--r--core/res/res/drawable/ic_notification_summarization.xml3
-rw-r--r--core/res/res/drawable/loader_horizontal_watch.xml103
-rw-r--r--core/res/res/layout/notification_2025_conversation_header.xml2
-rw-r--r--core/res/res/layout/notification_2025_template_collapsed_base.xml1
-rw-r--r--core/res/res/layout/notification_2025_template_collapsed_media.xml1
-rw-r--r--core/res/res/layout/notification_2025_template_collapsed_messaging.xml1
-rw-r--r--core/res/res/layout/notification_2025_template_compact_heads_up_base.xml1
-rw-r--r--core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml1
-rw-r--r--core/res/res/layout/notification_2025_template_header.xml26
-rw-r--r--core/res/res/layout/notification_template_header.xml24
-rw-r--r--core/res/res/values-af/strings.xml35
-rw-r--r--core/res/res/values-am/strings.xml33
-rw-r--r--core/res/res/values-ar/strings.xml31
-rw-r--r--core/res/res/values-as/strings.xml33
-rw-r--r--core/res/res/values-az/strings.xml33
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml25
-rw-r--r--core/res/res/values-be/strings.xml37
-rw-r--r--core/res/res/values-bg/strings.xml33
-rw-r--r--core/res/res/values-bn/strings.xml33
-rw-r--r--core/res/res/values-bs/strings.xml29
-rw-r--r--core/res/res/values-ca/strings.xml33
-rw-r--r--core/res/res/values-cs/strings.xml8
-rw-r--r--core/res/res/values-da/strings.xml33
-rw-r--r--core/res/res/values-de/strings.xml39
-rw-r--r--core/res/res/values-el/strings.xml35
-rw-r--r--core/res/res/values-en-rAU/strings.xml33
-rw-r--r--core/res/res/values-en-rCA/strings.xml25
-rw-r--r--core/res/res/values-en-rGB/strings.xml33
-rw-r--r--core/res/res/values-en-rIN/strings.xml33
-rw-r--r--core/res/res/values-es-rUS/strings.xml29
-rw-r--r--core/res/res/values-es/strings.xml33
-rw-r--r--core/res/res/values-et/strings.xml27
-rw-r--r--core/res/res/values-eu/strings.xml33
-rw-r--r--core/res/res/values-fa/strings.xml37
-rw-r--r--core/res/res/values-fi/strings.xml35
-rw-r--r--core/res/res/values-fr-rCA/strings.xml33
-rw-r--r--core/res/res/values-fr/strings.xml33
-rw-r--r--core/res/res/values-gl/strings.xml33
-rw-r--r--core/res/res/values-gu/strings.xml37
-rw-r--r--core/res/res/values-hi/strings.xml39
-rw-r--r--core/res/res/values-hr/strings.xml25
-rw-r--r--core/res/res/values-hu/strings.xml33
-rw-r--r--core/res/res/values-hy/strings.xml12
-rw-r--r--core/res/res/values-in/strings.xml33
-rw-r--r--core/res/res/values-is/strings.xml33
-rw-r--r--core/res/res/values-it/strings.xml45
-rw-r--r--core/res/res/values-iw/strings.xml14
-rw-r--r--core/res/res/values-ja/strings.xml25
-rw-r--r--core/res/res/values-ka/strings.xml25
-rw-r--r--core/res/res/values-kk/strings.xml35
-rw-r--r--core/res/res/values-km/strings.xml25
-rw-r--r--core/res/res/values-kn/strings.xml37
-rw-r--r--core/res/res/values-ko/strings.xml33
-rw-r--r--core/res/res/values-ky/strings.xml33
-rw-r--r--core/res/res/values-lo/strings.xml25
-rw-r--r--core/res/res/values-lt/strings.xml37
-rw-r--r--core/res/res/values-lv/strings.xml33
-rw-r--r--core/res/res/values-mk/strings.xml33
-rw-r--r--core/res/res/values-ml/strings.xml25
-rw-r--r--core/res/res/values-mn/strings.xml33
-rw-r--r--core/res/res/values-mr/strings.xml37
-rw-r--r--core/res/res/values-ms/strings.xml25
-rw-r--r--core/res/res/values-my/strings.xml33
-rw-r--r--core/res/res/values-nb/strings.xml33
-rw-r--r--core/res/res/values-ne/strings.xml44
-rw-r--r--core/res/res/values-nl/strings.xml25
-rw-r--r--core/res/res/values-or/strings.xml35
-rw-r--r--core/res/res/values-pa/strings.xml25
-rw-r--r--core/res/res/values-pl/strings.xml33
-rw-r--r--core/res/res/values-pt-rBR/strings.xml37
-rw-r--r--core/res/res/values-pt-rPT/strings.xml25
-rw-r--r--core/res/res/values-pt/strings.xml37
-rw-r--r--core/res/res/values-ro/strings.xml33
-rw-r--r--core/res/res/values-ru/strings.xml25
-rw-r--r--core/res/res/values-si/strings.xml12
-rw-r--r--core/res/res/values-sk/strings.xml27
-rw-r--r--core/res/res/values-sl/strings.xml27
-rw-r--r--core/res/res/values-sq/strings.xml33
-rw-r--r--core/res/res/values-sr/strings.xml25
-rw-r--r--core/res/res/values-sv/strings.xml33
-rw-r--r--core/res/res/values-sw/strings.xml33
-rw-r--r--core/res/res/values-ta/strings.xml33
-rw-r--r--core/res/res/values-te/strings.xml33
-rw-r--r--core/res/res/values-th/strings.xml25
-rw-r--r--core/res/res/values-tl/strings.xml29
-rw-r--r--core/res/res/values-tr/strings.xml33
-rw-r--r--core/res/res/values-uk/strings.xml14
-rw-r--r--core/res/res/values-ur/strings.xml37
-rw-r--r--core/res/res/values-uz/strings.xml29
-rw-r--r--core/res/res/values-vi/strings.xml33
-rw-r--r--core/res/res/values-w192dp/dimens_watch.xml28
-rw-r--r--core/res/res/values-w204dp-round-watch/dimens_watch.xml21
-rw-r--r--core/res/res/values-w216dp/dimens_watch.xml21
-rw-r--r--core/res/res/values-w228dp/dimens_watch.xml (renamed from services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/res/layout/input_view.xml)13
-rw-r--r--core/res/res/values-w240dp/dimens_material.xml4
-rw-r--r--core/res/res/values-watch/styles_device_defaults.xml3
-rw-r--r--core/res/res/values-zh-rCN/strings.xml35
-rw-r--r--core/res/res/values-zh-rHK/strings.xml33
-rw-r--r--core/res/res/values-zh-rTW/strings.xml33
-rw-r--r--core/res/res/values-zu/strings.xml33
-rw-r--r--core/res/res/values/attrs.xml1
-rw-r--r--core/res/res/values/config.xml11
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/dimens_watch.xml4
-rw-r--r--core/res/res/values/public-final.xml4
-rw-r--r--core/res/res/values/strings.xml49
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/tests/coretests/src/android/app/AutomaticZenRuleTest.java11
-rw-r--r--core/tests/coretests/src/android/app/NotificationManagerTest.java8
-rw-r--r--core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java34
-rw-r--r--core/tests/coretests/src/android/app/backup/DataTypeResultTest.java117
-rw-r--r--core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java21
-rw-r--r--core/tests/coretests/src/android/service/notification/ConditionTest.java13
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java10
-rw-r--r--core/tests/coretests/src/com/android/internal/util/RateLimitingCacheTest.java65
-rw-r--r--data/etc/platform.xml1
-rwxr-xr-xdata/fonts/script/test/test_commandline.py14
-rwxr-xr-xdata/fonts/script/test/test_xml_builder.py20
-rw-r--r--graphics/java/android/graphics/FrameInfo.java7
-rw-r--r--graphics/java/android/graphics/HardwareRenderer.java12
-rw-r--r--graphics/java/android/graphics/RuntimeShader.java38
-rw-r--r--keystore/java/android/security/GateKeeper.java2
-rw-r--r--keystore/java/android/security/keystore/ArrayUtils.java2
-rw-r--r--keystore/java/android/security/keystore/Utils.java2
-rw-r--r--keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java4
-rw-r--r--keystore/java/android/security/keystore2/KeymasterUtils.java46
-rw-r--r--libs/WindowManager/Shell/OWNERS2
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.pngbin0 -> 20393 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.pngbin0 -> 20220 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.pngbin0 -> 20319 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.pngbin0 -> 20401 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.pngbin0 -> 20635 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.pngbin0 -> 20522 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.pngbin0 -> 20569 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.pngbin0 -> 21304 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.pngbin0 -> 21159 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.pngbin0 -> 21276 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.pngbin0 -> 21283 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.pngbin0 -> 21318 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.pngbin0 -> 20400 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.pngbin0 -> 20082 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.pngbin0 -> 20406 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.pngbin0 -> 22270 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.pngbin0 -> 21917 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.pngbin0 -> 22462 bytes
-rw-r--r--libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt170
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt491
-rw-r--r--libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml54
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-bg/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings.xml24
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-de/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-es/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-eu/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-fi/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-gu/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-hu/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings.xml35
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-kk/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-ko/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-lo/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-lv/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-mk/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-mn/strings.xml35
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-my/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-or/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-sq/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-sv/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-sw/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings.xml35
-rw-r--r--libs/WindowManager/Shell/res/values-tr/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-uk/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values-zu/strings.xml33
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml19
-rw-r--r--libs/WindowManager/Shell/shared/res/color/bubble_drop_target_background_color.xml20
-rw-r--r--libs/WindowManager/Shell/shared/res/drawable/bubble_drop_target_background.xml25
-rw-r--r--libs/WindowManager/Shell/shared/res/values/dimen.xml10
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java45
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java11
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleBarLocation.kt6
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt24
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt90
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt98
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java44
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java292
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java279
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java143
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/WindowContainerTransactionSupplier.kt35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/CenterParallaxSpec.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DismissingParallaxSpec.java75
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/FlexParallaxSpec.java172
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/NoParallaxSpec.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/ParallaxSpec.java62
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/ResizingEffectPolicy.java177
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitState.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListener.kt66
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerFactory.kt43
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt38
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java412
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt256
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt412
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt104
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt491
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java218
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java129
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java196
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java197
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java331
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipTransitionUtils.java133
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentsAnimationRunner.aidl5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java62
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java65
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt41
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt63
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/SnapEventHandler.kt43
-rw-r--r--libs/WindowManager/Shell/tests/unittest/Android.bp1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java95
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java186
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/WindowContainerTransactionSupplierTest.kt42
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithmTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java)7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PhoneSizeSpecSourceTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhoneSizeSpecSourceTest.java)7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsAlgorithmTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java)11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsStateTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java)8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDoubleTapHelperTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java)6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipSnapAlgorithmTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipSnapAlgorithmTest.java)6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/FlexParallaxSpecTests.java401
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerFactoryTest.kt131
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerTest.kt146
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt137
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt170
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt458
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt67
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt250
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProviderTest.kt128
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt67
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt102
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java51
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTouchStateTest.java148
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandlerTest.java188
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java64
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java26
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt210
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt46
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java25
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt19
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java44
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt61
-rw-r--r--libs/androidfw/ApkAssets.cpp9
-rw-r--r--libs/androidfw/AssetManager2.cpp5
-rw-r--r--libs/androidfw/AssetsProvider.cpp91
-rw-r--r--libs/androidfw/Idmap.cpp21
-rw-r--r--libs/androidfw/LocaleDataLookup.cpp10
-rw-r--r--libs/androidfw/ResourceTypes.cpp78
-rw-r--r--libs/androidfw/Util.cpp25
-rw-r--r--libs/androidfw/include/androidfw/ApkAssets.h2
-rw-r--r--libs/androidfw/include/androidfw/AssetsProvider.h29
-rw-r--r--libs/androidfw/include/androidfw/Idmap.h32
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h48
-rw-r--r--libs/androidfw/include/androidfw/misc.h6
-rw-r--r--libs/androidfw/misc.cpp69
-rw-r--r--libs/androidfw/tests/Idmap_test.cpp27
-rw-r--r--libs/hwui/aconfig/hwui_flags.aconfig18
-rw-r--r--libs/hwui/jni/Shader.cpp15
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp16
-rw-r--r--location/Android.bp1
-rw-r--r--media/java/android/media/AudioDeviceVolumeManager.java55
-rw-r--r--media/java/android/media/AudioSystem.java15
-rw-r--r--media/java/android/media/MediaCodec.java2
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java167
-rw-r--r--media/java/android/media/RingtoneManager.java20
-rw-r--r--media/java/android/media/Utils.java6
-rw-r--r--media/jni/Android.bp36
-rw-r--r--media/jni/android_media_MediaPlayer.cpp20
-rw-r--r--media/jni/android_media_MediaRecorder.cpp2
-rw-r--r--nfc-extras/OWNERS2
-rw-r--r--nfc-non-updatable/OWNERS2
-rw-r--r--nfc-non-updatable/java/android/nfc/cardemulation/ApduServiceInfo.java31
-rw-r--r--omapi/OWNERS2
-rw-r--r--omapi/java/android/se/OWNERS2
-rw-r--r--omapi/java/android/se/omapi/OWNERS2
-rw-r--r--packages/CompanionDeviceManager/res/values-ar/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-be/strings.xml8
-rw-r--r--packages/CompanionDeviceManager/res/values-bs/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-da/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-de/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-el/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-es/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-et/strings.xml12
-rw-r--r--packages/CompanionDeviceManager/res/values-fa/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-fi/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-gu/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-hi/strings.xml8
-rw-r--r--packages/CompanionDeviceManager/res/values-hu/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-hy/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-it/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-iw/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-ka/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-kk/strings.xml10
-rw-r--r--packages/CompanionDeviceManager/res/values-kn/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-ky/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-lt/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-lv/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-mk/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-mr/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-nb/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-ne/strings.xml12
-rw-r--r--packages/CompanionDeviceManager/res/values-nl/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-or/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-pl/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-pt/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-ru/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-sk/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-sl/strings.xml8
-rw-r--r--packages/CompanionDeviceManager/res/values-sq/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-sr/strings.xml6
-rw-r--r--packages/CompanionDeviceManager/res/values-sv/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-te/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-tl/strings.xml4
-rw-r--r--packages/CompanionDeviceManager/res/values-ur/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml8
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml4
-rw-r--r--packages/CredentialManager/res/values-pl/strings.xml4
-rw-r--r--packages/LocalTransport/src/com/android/localtransport/LocalTransport.java18
-rw-r--r--packages/PackageInstaller/res/values-my/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-pt/strings.xml2
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp1
-rw-r--r--packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml5
-rw-r--r--packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt31
-rw-r--r--packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt6
-rw-r--r--packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/CollapsableTextView.kt47
-rw-r--r--packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt11
-rw-r--r--packages/SettingsLib/SettingsTransition/Android.bp1
-rw-r--r--packages/SettingsLib/TopIntroPreference/Android.bp1
-rw-r--r--packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml25
-rw-r--r--packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml25
-rw-r--r--packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml30
-rw-r--r--packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml26
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml71
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml28
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml80
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml22
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml54
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml26
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml78
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml22
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml67
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml26
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml76
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml20
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml65
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml24
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml74
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml18
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml63
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml22
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml72
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml20
-rw-r--r--packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml70
-rw-r--r--packages/SettingsLib/res/values-af/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-am/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ar/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-as/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-az/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-be/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bg/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bn/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bs/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ca/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-cs/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-da/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-de/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-el/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-en-rAU/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-en-rCA/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-en-rGB/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-en-rIN/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-es-rUS/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-es/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-et/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-eu/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fa/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fi/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fr/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gl/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gu/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-hi/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-hr/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-hu/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hy/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-in/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-is/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-it/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-iw/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ja/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ka/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-kk/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-km/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-kn/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ko/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ky/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lo/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-lt/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lv/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mk/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ml/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-mn/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mr/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ms/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-my/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-nb/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ne/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-nl/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-or/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pa/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pl/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-pt/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-ro/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ru/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-si/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sk/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-sl/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-sq/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sr/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-sv/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sw/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ta/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-te/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-th/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-tl/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-tr/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-uk/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ur/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-uz/arrays.xml9
-rw-r--r--packages/SettingsLib/res/values-vi/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zu/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values/strings.xml30
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java108
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java58
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/modes/EnableDndDialogFactory.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java47
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java86
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java55
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java14
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java1
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java5
-rw-r--r--packages/Shell/res/values-cs/strings.xml2
-rw-r--r--packages/Shell/res/values-pl/strings.xml2
-rw-r--r--packages/Shell/res/values-sl/strings.xml2
-rw-r--r--packages/SystemUI/Android.bp25
-rw-r--r--packages/SystemUI/OWNERS12
-rw-r--r--packages/SystemUI/aconfig/Android.bp1
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig76
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt57
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt56
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt297
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt38
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionToken.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/Icon.kt11
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt38
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt10
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt45
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt36
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt3
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt36
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt17
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt15
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt2
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt8
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt4
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt27
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt3
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt270
-rw-r--r--packages/SystemUI/docs/qs-tiles.md167
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java17
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryTest.kt113
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt60
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt17
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java25
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt540
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorTest.kt61
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt13
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt80
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt97
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt68
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt42
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt17
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt39
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt49
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelTest.kt17
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt162
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java)100
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt37
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt26
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt24
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt42
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt83
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt337
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt183
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingStateTest.kt237
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorTest.kt117
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt65
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt75
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java22
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java209
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt243
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt82
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt118
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt14
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt90
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt30
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierTest.kt162
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt156
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java11
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt12
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java11
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java37
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColorRule.java39
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColors.java30
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java194
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt63
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt129
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt116
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModelTest.kt148
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModelTest.kt35
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt15
-rw-r--r--packages/SystemUI/res-keyguard/drawable/pin_bouncer_confirm.xml31
-rw-r--r--packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_filled.xml25
-rw-r--r--packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_outline.xml31
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml2
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_password_motion_layout.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml27
-rw-r--r--packages/SystemUI/res/drawable/ic_speaker_mute.xml23
-rw-r--r--packages/SystemUI/res/drawable/ic_speaker_on.xml23
-rw-r--r--packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml47
-rw-r--r--packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml30
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml2
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml2
-rw-r--r--packages/SystemUI/res/layout/battery_status_chip.xml12
-rw-r--r--packages/SystemUI/res/layout/bindable_status_bar_compose_icon.xml33
-rw-r--r--packages/SystemUI/res/layout/internet_connectivity_dialog.xml2
-rw-r--r--packages/SystemUI/res/layout/magic_action_button.xml3
-rw-r--r--packages/SystemUI/res/layout/media_session_view.xml2
-rw-r--r--packages/SystemUI/res/layout/notification_2025_hybrid.xml1
-rw-r--r--packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml1
-rw-r--r--packages/SystemUI/res/layout/promoted_notification_info.xml36
-rw-r--r--packages/SystemUI/res/layout/status_bar_event_chip_compose.xml34
-rw-r--r--packages/SystemUI/res/layout/volume_dialog.xml38
-rw-r--r--packages/SystemUI/res/layout/volume_dialog_bottom_section.xml26
-rw-r--r--packages/SystemUI/res/layout/volume_dialog_top_section.xml (renamed from packages/SystemUI/res/layout/volume_ringer_drawer.xml)5
-rw-r--r--packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml6
-rw-r--r--packages/SystemUI/res/values-af/strings.xml17
-rw-r--r--packages/SystemUI/res/values-am/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml17
-rw-r--r--packages/SystemUI/res/values-as/strings.xml5
-rw-r--r--packages/SystemUI/res/values-az/strings.xml17
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml12
-rw-r--r--packages/SystemUI/res/values-be/strings.xml4
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml17
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml17
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml19
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml19
-rw-r--r--packages/SystemUI/res/values-da/strings.xml5
-rw-r--r--packages/SystemUI/res/values-de/strings.xml19
-rw-r--r--packages/SystemUI/res/values-el/strings.xml17
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml17
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml17
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml17
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml8
-rw-r--r--packages/SystemUI/res/values-es/strings.xml17
-rw-r--r--packages/SystemUI/res/values-et/strings.xml6
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml19
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml17
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml17
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml19
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml5
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml18
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml20
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml4
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml19
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml17
-rw-r--r--packages/SystemUI/res/values-in/strings.xml17
-rw-r--r--packages/SystemUI/res/values-is/strings.xml5
-rw-r--r--packages/SystemUI/res/values-it/strings.xml8
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml34
-rw-r--r--packages/SystemUI/res/values-iw/tiles_states_strings.xml2
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml24
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml16
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml19
-rw-r--r--packages/SystemUI/res/values-km/strings.xml4
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml17
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml16
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml10
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml19
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml4
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml17
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml6
-rw-r--r--packages/SystemUI/res/values-my/strings.xml17
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml27
-rw-r--r--packages/SystemUI/res/values-night/colors.xml10
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml4
-rw-r--r--packages/SystemUI/res/values-or/strings.xml19
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml4
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml10
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml4
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml6
-rw-r--r--packages/SystemUI/res/values-si/strings.xml5
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml17
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml12
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml17
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml17
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml23
-rw-r--r--packages/SystemUI/res/values-te/strings.xml9
-rw-r--r--packages/SystemUI/res/values-th/strings.xml4
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml13
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml19
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml23
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml18
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml5
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml17
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml17
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml19
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml17
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml17
-rw-r--r--packages/SystemUI/res/values/colors.xml10
-rw-r--r--packages/SystemUI/res/values/config.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml54
-rw-r--r--packages/SystemUI/res/values/strings.xml12
-rw-r--r--packages/SystemUI/res/values/styles.xml13
-rw-r--r--packages/SystemUI/res/values/tiles_states_strings.xml10
-rw-r--r--packages/SystemUI/res/xml/media_session_collapsed.xml7
-rw-r--r--packages/SystemUI/res/xml/volume_dialog_constraint_set.xml2
-rw-r--r--packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml2
-rw-r--r--packages/SystemUI/res/xml/volume_dialog_ringer_drawer_motion_scene.xml29
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java66
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java45
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadButton.java28
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadKey.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegate.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/activity/data/model/AppVisibilityModel.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/activity/data/repository/ActivityManagerRepository.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContent.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt (renamed from packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt)9
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt183
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractor.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/decor/ScreenDecorCommand.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/homecontrols/service/TaskFragmentComponent.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java234
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt108
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt156
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelListUpdateCallback.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java575
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java409
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java (renamed from packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java)311
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogV2.kt113
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt134
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacy.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsContent.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt98
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTileSet.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/BaseShadeControllerImpl.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/ShadeColors.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt82
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingState.kt122
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt100
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/MediaControlChipStartable.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractor.kt75
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineEntry.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java104
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationStackOptionalModule.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt143
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt90
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java84
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt265
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionButton.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java72
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/icons/shared/BindableIconsRegistry.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/StackedMobileBindableIcon.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/StackedMobileIconBinder.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModel.kt90
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StackedMobileIcon.kt180
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarComposeIconView.kt155
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java122
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/repository/SecureSettingsForUserRepository.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/repository/SettingsForUserRepository.kt66
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/ViewBinder.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt108
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/JankListenerFactory.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/panel/shared/VolumePanelLogger.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt143
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/window/data/repository/NoopWindowRootViewBlurRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModel.kt55
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/OnTeardownRuleTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/OnTeardownRuleTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegateTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegateTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManagerTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt)34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogEulogizerTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java166
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/lifecycle/HydratorTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/HydratorTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/QSFragmentComposeTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/QSFragmentComposeTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/TestMatchers.kt52
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt845
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt)55
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt)53
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/layout/StatusBarBoundsProviderTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/layout/StatusBarBoundsProviderTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java148
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java51
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java)11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/user/CreateUserActivityTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java)0
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt)0
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryKosmos.kt56
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelFactoryKosmos.kt7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt13
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationEntryBuilderKosmos.kt90
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotifPipelineKosmos.kt5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt14
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorKosmos.kt)15
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorKosmos.kt33
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/data/repository/SecureSettingsForUserRepositoryKosmos.kt (renamed from packages/SystemUI/src/com/android/systemui/common/shared/colors/ShadeColors.kt)22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinderKosmos.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt9
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt21
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepositoryKosmos.kt1
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java229
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java17
-rw-r--r--ravenwood/runtime-jni/ravenwood_initializer.cpp77
-rw-r--r--ravenwood/texts/ravenwood-standard-options.txt4
-rw-r--r--ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java43
-rw-r--r--ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt1
-rw-r--r--ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt51
-rw-r--r--ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt120
-rw-r--r--ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt230
-rw-r--r--services/accessibility/accessibility.aconfig7
-rw-r--r--services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java4
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java5
-rw-r--r--services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java92
-rw-r--r--services/core/Android.bp5
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java15
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java8
-rw-r--r--services/core/java/com/android/server/am/AppStartInfoTracker.java40
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java7
-rw-r--r--services/core/java/com/android/server/am/UserController.java38
-rw-r--r--services/core/java/com/android/server/am/flags.aconfig18
-rw-r--r--services/core/java/com/android/server/appbinding/AppBindingConstants.java13
-rw-r--r--services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java83
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java84
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java155
-rw-r--r--services/core/java/com/android/server/audio/AudioSystemAdapter.java4
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java52
-rw-r--r--services/core/java/com/android/server/backup/SystemBackupAgent.java8
-rw-r--r--services/core/java/com/android/server/backup/WearBackupHelper.java49
-rw-r--r--services/core/java/com/android/server/backup/WearBackupInternal.java32
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java18
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java29
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java19
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java14
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java13
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java15
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java48
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java24
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig14
-rw-r--r--services/core/java/com/android/server/flags/people.aconfig12
-rw-r--r--services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java8
-rw-r--r--services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java14
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java8
-rw-r--r--services/core/java/com/android/server/input/InputManagerInternal.java38
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java60
-rw-r--r--services/core/java/com/android/server/input/NativeInputManagerService.java13
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java29
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java3
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java26
-rw-r--r--services/core/java/com/android/server/media/quality/MediaQualityService.java140
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java293
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java243
-rw-r--r--services/core/java/com/android/server/notification/NotificationShellCmd.java9
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java88
-rw-r--r--services/core/java/com/android/server/notification/ZenModeEventLogger.java117
-rw-r--r--services/core/java/com/android/server/notification/ZenModeFiltering.java11
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java622
-rw-r--r--services/core/java/com/android/server/notification/flags.aconfig7
-rw-r--r--services/core/java/com/android/server/pm/BackgroundInstallControlService.java35
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java29
-rw-r--r--services/core/java/com/android/server/pm/InstallingSession.java24
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java13
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java12
-rw-r--r--services/core/java/com/android/server/resources/ResourcesManagerShellCommand.java1
-rw-r--r--services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java6
-rw-r--r--services/core/java/com/android/server/security/CertificateRevocationStatusManager.java45
-rw-r--r--services/core/java/com/android/server/security/FileIntegrityService.java5
-rw-r--r--services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java2
-rw-r--r--services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java4
-rw-r--r--services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java15
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java14
-rw-r--r--services/core/java/com/android/server/updates/CertPinInstallReceiver.java10
-rw-r--r--services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java3
-rw-r--r--services/core/java/com/android/server/wearable/WearableSensingSecureChannel.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java230
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java16
-rw-r--r--services/core/java/com/android/server/wm/AppCompatController.java8
-rw-r--r--services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java65
-rw-r--r--services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java8
-rw-r--r--services/core/java/com/android/server/wm/AppCompatUtils.java12
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java29
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java4
-rw-r--r--services/core/java/com/android/server/wm/DeferredDisplayUpdater.java8
-rw-r--r--services/core/java/com/android/server/wm/DesktopModeHelper.java38
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java54
-rw-r--r--services/core/java/com/android/server/wm/DragState.java55
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java24
-rw-r--r--services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java227
-rw-r--r--services/core/java/com/android/server/wm/RemoteAnimationController.java636
-rw-r--r--services/core/java/com/android/server/wm/Task.java3
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java13
-rw-r--r--services/core/java/com/android/server/wm/Transition.java5
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java13
-rw-r--r--services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java191
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java25
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java66
-rw-r--r--services/core/java/com/android/server/wm/WindowContainerThumbnail.java218
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java51
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp34
-rw-r--r--services/people/java/com/android/server/people/PeopleService.java14
-rw-r--r--services/supervision/java/com/android/server/supervision/SupervisionService.java40
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml4
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java884
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java5
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/res/xml/method.xml11
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/KeyCodeConstants.java85
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleInputMethodService.java44
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleKeyboard.java132
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleKeyboardView.java191
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java73
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java51
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java43
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java67
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java11
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java30
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java86
-rw-r--r--services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java36
-rw-r--r--services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java43
-rw-r--r--services/tests/powerstatstests/res/raw/battery-history.zipbin0 -> 272063 bytes
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java179
-rw-r--r--services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java178
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java74
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/AudioDeviceInventoryTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java2
-rw-r--r--services/tests/uiservicestests/Android.bp1
-rw-r--r--services/tests/uiservicestests/src/android/app/NotificationManagerZenTest.java12
-rw-r--r--services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java4
-rw-r--r--services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java4
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java24
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java496
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java257
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java127
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java8
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java22
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java7
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java57
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java88
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java3
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java795
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java35
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java68
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java757
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java43
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java65
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java39
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java15
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java48
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl11
-rw-r--r--tests/AppJankTest/res/values/strings.xml3
-rw-r--r--tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java3
-rw-r--r--tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java26
-rw-r--r--tests/AttestationVerificationTest/src/com/android/server/security/CertificateRevocationStatusManagerTest.java66
-rw-r--r--tests/Input/src/com/android/server/input/InputManagerServiceTests.kt30
-rw-r--r--tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java58
-rw-r--r--tests/testables/tests/src/android/animation/AnimatorTestRuleToolkitTest.kt21
-rw-r--r--tests/utils/testutils/java/android/os/test/TestLooper.java168
-rw-r--r--tests/vcn/Android.bp10
-rw-r--r--tests/vcn/AndroidManifest.xml5
-rw-r--r--tests/vcn/AndroidTest.xml10
-rw-r--r--tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java13
-rw-r--r--tests/vcn/java/android/net/vcn/VcnConfigTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/VcnManagerTest.java12
-rw-r--r--tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java12
-rw-r--r--tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java12
-rw-r--r--tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/VcnUtilsTest.java12
-rw-r--r--tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java13
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java9
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java10
-rw-r--r--tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java10
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java10
-rw-r--r--tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java10
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java10
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java11
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java11
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java12
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java12
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java10
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java10
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnTest.java11
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java11
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java12
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java11
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java11
-rw-r--r--tools/aapt2/Debug.cpp28
-rw-r--r--tools/aapt2/cmd/Diff.cpp183
-rw-r--r--tools/aapt2/cmd/Diff.h15
1533 files changed, 35451 insertions, 19654 deletions
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
index ecbfc7169945..10ec2bfcb49a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -75,8 +75,19 @@ public class ExpensiveObjectsPerfTest {
@Test(timeout = 900000)
public void timeNewCollator() {
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 0;
while (state.keepRunning()) {
Collator.getInstance(Locale.US);
+
+ if (++i % 1000 == 0) {
+ state.pauseTiming();
+ // GC and finalize occasionally to avoid GC for alloc and/or
+ // blocking on finalization during benchmark time.
+ // See: b/394961590
+ System.gc();
+ System.runFinalization();
+ state.resumeTiming();
+ }
}
}
@@ -84,8 +95,19 @@ public class ExpensiveObjectsPerfTest {
public void timeClonedCollator() {
Collator c = Collator.getInstance(Locale.US);
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int i = 0;
while (state.keepRunning()) {
c.clone();
+
+ if (++i % 1000 == 0) {
+ state.pauseTiming();
+ // GC and finalize occasionally to avoid GC for alloc and/or
+ // blocking on finalization during benchmark time.
+ // See: b/394961590
+ System.gc();
+ System.runFinalization();
+ state.resumeTiming();
+ }
}
}
diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig
index 86ed06bf4e3d..29df80fda33d 100644
--- a/apex/jobscheduler/service/aconfig/job.aconfig
+++ b/apex/jobscheduler/service/aconfig/job.aconfig
@@ -105,4 +105,14 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
-} \ No newline at end of file
+}
+
+flag {
+ name: "include_trace_tag_in_job_name"
+ namespace: "backstage_power"
+ description: "Add the trace tag to the job name"
+ bug: "354795473"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index aaf69864fe97..2d069f934d0d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -674,6 +674,12 @@ public final class JobStatus {
this.job = job;
StringBuilder batteryName = new StringBuilder();
+ if (com.android.server.job.Flags.includeTraceTagInJobName()) {
+ final String filteredTraceTag = this.getFilteredTraceTag();
+ if (filteredTraceTag != null) {
+ batteryName.append("#").append(filteredTraceTag).append("#");
+ }
+ }
if (namespace != null) {
batteryName.append("@").append(namespace).append("@");
}
diff --git a/cmds/svc/src/com/android/commands/svc/OWNERS b/cmds/svc/src/com/android/commands/svc/OWNERS
index d5a5d7b3b858..a901dfdeddfb 100644
--- a/cmds/svc/src/com/android/commands/svc/OWNERS
+++ b/cmds/svc/src/com/android/commands/svc/OWNERS
@@ -1,2 +1,2 @@
# Bug component: 48448
-per-file NfcCommand.java = file:platform/packages/apps/Nfc:/OWNERS
+per-file NfcCommand.java = file:platform/packages/modules/Nfc:/OWNERS
diff --git a/core/api/current.txt b/core/api/current.txt
index d4ed533cad9e..5c0ecf72030f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -100,6 +100,9 @@ package android {
field public static final String EXECUTE_APP_ACTION = "android.permission.EXECUTE_APP_ACTION";
field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String EXECUTE_APP_FUNCTIONS = "android.permission.EXECUTE_APP_FUNCTIONS";
field public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String EYE_TRACKING_COARSE = "android.permission.EYE_TRACKING_COARSE";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String EYE_TRACKING_FINE = "android.permission.EYE_TRACKING_FINE";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String FACE_TRACKING = "android.permission.FACE_TRACKING";
field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST";
field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
field public static final String FOREGROUND_SERVICE_CAMERA = "android.permission.FOREGROUND_SERVICE_CAMERA";
@@ -120,6 +123,8 @@ package android {
field public static final String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
field @Deprecated public static final String GET_TASKS = "android.permission.GET_TASKS";
field public static final String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String HAND_TRACKING = "android.permission.HAND_TRACKING";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String HEAD_TRACKING = "android.permission.HEAD_TRACKING";
field public static final String HIDE_OVERLAY_WINDOWS = "android.permission.HIDE_OVERLAY_WINDOWS";
field public static final String HIGH_SAMPLING_RATE_SENSORS = "android.permission.HIGH_SAMPLING_RATE_SENSORS";
field public static final String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -295,6 +300,8 @@ package android {
field public static final String REQUEST_PASSWORD_COMPLEXITY = "android.permission.REQUEST_PASSWORD_COMPLEXITY";
field @Deprecated public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final String RUN_USER_INITIATED_JOBS = "android.permission.RUN_USER_INITIATED_JOBS";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String SCENE_UNDERSTANDING_COARSE = "android.permission.SCENE_UNDERSTANDING_COARSE";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String SCENE_UNDERSTANDING_FINE = "android.permission.SCENE_UNDERSTANDING_FINE";
field public static final String SCHEDULE_EXACT_ALARM = "android.permission.SCHEDULE_EXACT_ALARM";
field public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final String SEND_SMS = "android.permission.SEND_SMS";
@@ -362,6 +369,8 @@ package android {
field public static final String SENSORS = "android.permission-group.SENSORS";
field public static final String SMS = "android.permission-group.SMS";
field public static final String STORAGE = "android.permission-group.STORAGE";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_TRACKING = "android.permission-group.XR_TRACKING";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_TRACKING_SENSITIVE = "android.permission-group.XR_TRACKING_SENSITIVE";
}
public final class R {
@@ -5479,37 +5488,37 @@ package android.app {
method public android.net.Uri getConditionId();
method @Nullable public android.content.ComponentName getConfigurationActivity();
method public long getCreationTime();
- method @FlaggedApi("android.app.modes_api") @Nullable public android.service.notification.ZenDeviceEffects getDeviceEffects();
- method @FlaggedApi("android.app.modes_api") @DrawableRes public int getIconResId();
+ method @Nullable public android.service.notification.ZenDeviceEffects getDeviceEffects();
+ method @DrawableRes public int getIconResId();
method public int getInterruptionFilter();
method public String getName();
method public android.content.ComponentName getOwner();
- method @FlaggedApi("android.app.modes_api") @Nullable public String getTriggerDescription();
- method @FlaggedApi("android.app.modes_api") public int getType();
+ method @Nullable public String getTriggerDescription();
+ method public int getType();
method @Nullable public android.service.notification.ZenPolicy getZenPolicy();
method public boolean isEnabled();
- method @FlaggedApi("android.app.modes_api") public boolean isManualInvocationAllowed();
+ method public boolean isManualInvocationAllowed();
method public void setConditionId(android.net.Uri);
method public void setConfigurationActivity(@Nullable android.content.ComponentName);
- method @FlaggedApi("android.app.modes_api") public void setDeviceEffects(@Nullable android.service.notification.ZenDeviceEffects);
+ method public void setDeviceEffects(@Nullable android.service.notification.ZenDeviceEffects);
method public void setEnabled(boolean);
method public void setInterruptionFilter(int);
method public void setName(String);
method public void setZenPolicy(@Nullable android.service.notification.ZenPolicy);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
- field @FlaggedApi("android.app.modes_api") public static final int TYPE_BEDTIME = 3; // 0x3
- field @FlaggedApi("android.app.modes_api") public static final int TYPE_DRIVING = 4; // 0x4
- field @FlaggedApi("android.app.modes_api") public static final int TYPE_IMMERSIVE = 5; // 0x5
- field @FlaggedApi("android.app.modes_api") public static final int TYPE_MANAGED = 7; // 0x7
- field @FlaggedApi("android.app.modes_api") public static final int TYPE_OTHER = 0; // 0x0
- field @FlaggedApi("android.app.modes_api") public static final int TYPE_SCHEDULE_CALENDAR = 2; // 0x2
- field @FlaggedApi("android.app.modes_api") public static final int TYPE_SCHEDULE_TIME = 1; // 0x1
- field @FlaggedApi("android.app.modes_api") public static final int TYPE_THEATER = 6; // 0x6
- field @FlaggedApi("android.app.modes_api") public static final int TYPE_UNKNOWN = -1; // 0xffffffff
- }
-
- @FlaggedApi("android.app.modes_api") public static final class AutomaticZenRule.Builder {
+ field public static final int TYPE_BEDTIME = 3; // 0x3
+ field public static final int TYPE_DRIVING = 4; // 0x4
+ field public static final int TYPE_IMMERSIVE = 5; // 0x5
+ field public static final int TYPE_MANAGED = 7; // 0x7
+ field public static final int TYPE_OTHER = 0; // 0x0
+ field public static final int TYPE_SCHEDULE_CALENDAR = 2; // 0x2
+ field public static final int TYPE_SCHEDULE_TIME = 1; // 0x1
+ field public static final int TYPE_THEATER = 6; // 0x6
+ field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ }
+
+ public static final class AutomaticZenRule.Builder {
ctor public AutomaticZenRule.Builder(@NonNull android.app.AutomaticZenRule);
ctor public AutomaticZenRule.Builder(@NonNull String, @NonNull android.net.Uri);
method @NonNull public android.app.AutomaticZenRule build();
@@ -7127,7 +7136,7 @@ package android.app {
public class NotificationManager {
method public String addAutomaticZenRule(android.app.AutomaticZenRule);
- method @FlaggedApi("android.app.modes_api") public boolean areAutomaticZenRulesUserManaged();
+ method public boolean areAutomaticZenRulesUserManaged();
method @Deprecated public boolean areBubblesAllowed();
method public boolean areBubblesEnabled();
method public boolean areNotificationsEnabled();
@@ -7147,7 +7156,7 @@ package android.app {
method public void deleteNotificationChannelGroup(String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.app.AutomaticZenRule getAutomaticZenRule(String);
- method @FlaggedApi("android.app.modes_api") public int getAutomaticZenRuleState(@NonNull String);
+ method public int getAutomaticZenRuleState(@NonNull String);
method public java.util.Map<java.lang.String,android.app.AutomaticZenRule> getAutomaticZenRules();
method public int getBubblePreference();
method @NonNull public android.app.NotificationManager.Policy getConsolidatedNotificationPolicy();
@@ -7176,14 +7185,14 @@ package android.app {
field public static final String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
field public static final String ACTION_AUTOMATIC_ZEN_RULE = "android.app.action.AUTOMATIC_ZEN_RULE";
field public static final String ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED = "android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED";
- field @FlaggedApi("android.app.modes_api") public static final String ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED = "android.app.action.CONSOLIDATED_NOTIFICATION_POLICY_CHANGED";
+ field public static final String ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED = "android.app.action.CONSOLIDATED_NOTIFICATION_POLICY_CHANGED";
field public static final String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
field public static final String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
field public static final String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
field public static final String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
- field @FlaggedApi("android.app.modes_api") public static final int AUTOMATIC_RULE_STATUS_ACTIVATED = 4; // 0x4
- field @FlaggedApi("android.app.modes_api") public static final int AUTOMATIC_RULE_STATUS_DEACTIVATED = 5; // 0x5
+ field public static final int AUTOMATIC_RULE_STATUS_ACTIVATED = 4; // 0x4
+ field public static final int AUTOMATIC_RULE_STATUS_DEACTIVATED = 5; // 0x5
field public static final int AUTOMATIC_RULE_STATUS_DISABLED = 2; // 0x2
field public static final int AUTOMATIC_RULE_STATUS_ENABLED = 1; // 0x1
field public static final int AUTOMATIC_RULE_STATUS_REMOVED = 3; // 0x3
@@ -7197,7 +7206,7 @@ package android.app {
field public static final String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
field public static final String EXTRA_NOTIFICATION_CHANNEL_GROUP_ID = "android.app.extra.NOTIFICATION_CHANNEL_GROUP_ID";
field public static final String EXTRA_NOTIFICATION_CHANNEL_ID = "android.app.extra.NOTIFICATION_CHANNEL_ID";
- field @FlaggedApi("android.app.modes_api") public static final String EXTRA_NOTIFICATION_POLICY = "android.app.extra.NOTIFICATION_POLICY";
+ field public static final String EXTRA_NOTIFICATION_POLICY = "android.app.extra.NOTIFICATION_POLICY";
field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
field public static final int IMPORTANCE_HIGH = 4; // 0x4
field public static final int IMPORTANCE_LOW = 2; // 0x2
@@ -9188,6 +9197,14 @@ package android.app.blob {
}
+package android.app.contextualsearch {
+
+ @FlaggedApi("android.app.contextualsearch.flags.self_invocation") public final class ContextualSearchManager {
+ method @FlaggedApi("android.app.contextualsearch.flags.self_invocation") public void startContextualSearch();
+ }
+
+}
+
package android.app.jank {
@FlaggedApi("android.app.jank.detailed_app_jank_metrics_api") public final class AppJankStats {
@@ -17604,6 +17621,7 @@ package android.graphics {
method public void setIntUniform(@NonNull String, int, int, int);
method public void setIntUniform(@NonNull String, int, int, int, int);
method public void setIntUniform(@NonNull String, @NonNull int[]);
+ method @FlaggedApi("com.android.graphics.hwui.flags.shader_color_space") public void setWorkingColorSpace(@Nullable android.graphics.ColorSpace);
}
@FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public class RuntimeXfermode extends android.graphics.Xfermode {
@@ -25039,8 +25057,10 @@ package android.media {
method public final void notifySessionCreated(long, @NonNull android.media.RoutingSessionInfo);
method public final void notifySessionReleased(@NonNull String);
method public final void notifySessionUpdated(@NonNull android.media.RoutingSessionInfo);
+ method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @Nullable @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public final android.media.MediaRoute2ProviderService.MediaStreams notifySystemRoutingSessionCreated(long, @NonNull android.media.RoutingSessionInfo, @NonNull android.media.MediaRoute2ProviderService.MediaStreamsFormats);
method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onCreateSession(long, @NonNull String, @NonNull String, @Nullable android.os.Bundle);
+ method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public void onCreateSystemRoutingSession(long, @NonNull String, @NonNull android.media.MediaRoute2ProviderService.SystemRoutingSessionParams);
method public abstract void onDeselectRoute(long, @NonNull String, @NonNull String);
method public void onDiscoveryPreferenceChanged(@NonNull android.media.RouteDiscoveryPreference);
method public abstract void onReleaseSession(long, @NonNull String);
@@ -25048,15 +25068,44 @@ package android.media {
method public abstract void onSetRouteVolume(long, @NonNull String, int);
method public abstract void onSetSessionVolume(long, @NonNull String, int);
method public abstract void onTransferToRoute(long, @NonNull String, @NonNull String);
+ field @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final String CATEGORY_SYSTEM_MEDIA = "android.media.MediaRoute2ProviderService.SYSTEM_MEDIA";
+ field @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final int REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA = 6; // 0x6
field public static final int REASON_INVALID_COMMAND = 4; // 0x4
field public static final int REASON_NETWORK_ERROR = 2; // 0x2
field public static final int REASON_REJECTED = 1; // 0x1
field public static final int REASON_ROUTE_NOT_AVAILABLE = 3; // 0x3
+ field @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final int REASON_UNIMPLEMENTED = 5; // 0x5
field public static final int REASON_UNKNOWN_ERROR = 0; // 0x0
field public static final long REQUEST_ID_NONE = 0L; // 0x0L
field public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService";
}
+ @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final class MediaRoute2ProviderService.MediaStreams {
+ method @Nullable public android.media.AudioRecord getAudioRecord();
+ }
+
+ @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final class MediaRoute2ProviderService.MediaStreamsFormats {
+ method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @Nullable public android.media.AudioFormat getAudioFormat();
+ }
+
+ @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final class MediaRoute2ProviderService.MediaStreamsFormats.Builder {
+ ctor public MediaRoute2ProviderService.MediaStreamsFormats.Builder();
+ method @NonNull public android.media.MediaRoute2ProviderService.MediaStreamsFormats build();
+ method @NonNull public android.media.MediaRoute2ProviderService.MediaStreamsFormats.Builder setAudioFormat(@NonNull android.media.AudioFormat);
+ }
+
+ @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final class MediaRoute2ProviderService.SystemRoutingSessionParams {
+ method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @NonNull public android.os.Bundle getExtras();
+ method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @NonNull public String getPackageName();
+ }
+
+ public static final class MediaRoute2ProviderService.SystemRoutingSessionParams.Builder {
+ ctor public MediaRoute2ProviderService.SystemRoutingSessionParams.Builder();
+ method @NonNull public android.media.MediaRoute2ProviderService.SystemRoutingSessionParams build();
+ method @NonNull public android.media.MediaRoute2ProviderService.SystemRoutingSessionParams.Builder setExtras(@NonNull android.os.Bundle);
+ method @NonNull public android.media.MediaRoute2ProviderService.SystemRoutingSessionParams.Builder setPackageName(@NonNull String);
+ }
+
public class MediaRouter {
method public void addCallback(int, android.media.MediaRouter.Callback);
method public void addCallback(int, android.media.MediaRouter.Callback, int);
@@ -38232,7 +38281,7 @@ package android.provider {
field public static final String ACTION_APP_OPEN_BY_DEFAULT_SETTINGS = "android.settings.APP_OPEN_BY_DEFAULT_SETTINGS";
field public static final String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS";
field public static final String ACTION_APP_USAGE_SETTINGS = "android.settings.action.APP_USAGE_SETTINGS";
- field @FlaggedApi("android.app.modes_api") public static final String ACTION_AUTOMATIC_ZEN_RULE_SETTINGS = "android.settings.AUTOMATIC_ZEN_RULE_SETTINGS";
+ field public static final String ACTION_AUTOMATIC_ZEN_RULE_SETTINGS = "android.settings.AUTOMATIC_ZEN_RULE_SETTINGS";
field public static final String ACTION_AUTO_ROTATE_SETTINGS = "android.settings.AUTO_ROTATE_SETTINGS";
field public static final String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS";
field public static final String ACTION_BIOMETRIC_ENROLL = "android.settings.BIOMETRIC_ENROLL";
@@ -38326,7 +38375,7 @@ package android.provider {
field public static final String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
field public static final String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
field public static final String EXTRA_AUTHORITIES = "authorities";
- field @FlaggedApi("android.app.modes_api") public static final String EXTRA_AUTOMATIC_ZEN_RULE_ID = "android.provider.extra.AUTOMATIC_ZEN_RULE_ID";
+ field public static final String EXTRA_AUTOMATIC_ZEN_RULE_ID = "android.provider.extra.AUTOMATIC_ZEN_RULE_ID";
field public static final String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
field public static final String EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED = "android.provider.extra.BIOMETRIC_AUTHENTICATORS_ALLOWED";
field public static final String EXTRA_CHANNEL_FILTER_LIST = "android.provider.extra.CHANNEL_FILTER_LIST";
@@ -42118,9 +42167,9 @@ package android.service.notification {
public final class Condition implements android.os.Parcelable {
ctor public Condition(android.net.Uri, String, int);
- ctor @FlaggedApi("android.app.modes_api") public Condition(@Nullable android.net.Uri, @Nullable String, int, int);
+ ctor public Condition(@Nullable android.net.Uri, @Nullable String, int, int);
ctor public Condition(android.net.Uri, String, String, String, int, int, int);
- ctor @FlaggedApi("android.app.modes_api") public Condition(@Nullable android.net.Uri, @Nullable String, @Nullable String, @Nullable String, int, int, int, int);
+ ctor public Condition(@Nullable android.net.Uri, @Nullable String, @Nullable String, @Nullable String, int, int, int, int);
ctor public Condition(android.os.Parcel);
method public android.service.notification.Condition copy();
method public int describeContents();
@@ -42133,10 +42182,10 @@ package android.service.notification {
field public static final int FLAG_RELEVANT_ALWAYS = 2; // 0x2
field public static final int FLAG_RELEVANT_NOW = 1; // 0x1
field public static final String SCHEME = "condition";
- field @FlaggedApi("android.app.modes_api") public static final int SOURCE_CONTEXT = 3; // 0x3
- field @FlaggedApi("android.app.modes_api") public static final int SOURCE_SCHEDULE = 2; // 0x2
- field @FlaggedApi("android.app.modes_api") public static final int SOURCE_UNKNOWN = 0; // 0x0
- field @FlaggedApi("android.app.modes_api") public static final int SOURCE_USER_ACTION = 1; // 0x1
+ field public static final int SOURCE_CONTEXT = 3; // 0x3
+ field public static final int SOURCE_SCHEDULE = 2; // 0x2
+ field public static final int SOURCE_UNKNOWN = 0; // 0x0
+ field public static final int SOURCE_USER_ACTION = 1; // 0x1
field public static final int STATE_ERROR = 3; // 0x3
field public static final int STATE_FALSE = 0; // 0x0
field public static final int STATE_TRUE = 1; // 0x1
@@ -42146,7 +42195,7 @@ package android.service.notification {
field public final android.net.Uri id;
field public final String line1;
field public final String line2;
- field @FlaggedApi("android.app.modes_api") public final int source;
+ field public final int source;
field public final int state;
field public final String summary;
}
@@ -42317,7 +42366,7 @@ package android.service.notification {
field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.StatusBarNotification> CREATOR;
}
- @FlaggedApi("android.app.modes_api") public final class ZenDeviceEffects implements android.os.Parcelable {
+ public final class ZenDeviceEffects implements android.os.Parcelable {
method public int describeContents();
method public boolean shouldDimWallpaper();
method public boolean shouldDisplayGrayscale();
@@ -42327,7 +42376,7 @@ package android.service.notification {
field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.ZenDeviceEffects> CREATOR;
}
- @FlaggedApi("android.app.modes_api") public static final class ZenDeviceEffects.Builder {
+ public static final class ZenDeviceEffects.Builder {
ctor public ZenDeviceEffects.Builder();
ctor public ZenDeviceEffects.Builder(@NonNull android.service.notification.ZenDeviceEffects);
method @NonNull public android.service.notification.ZenDeviceEffects build();
@@ -42349,7 +42398,7 @@ package android.service.notification {
method public int getPriorityCategoryReminders();
method public int getPriorityCategoryRepeatCallers();
method public int getPriorityCategorySystem();
- method @FlaggedApi("android.app.modes_api") public int getPriorityChannelsAllowed();
+ method public int getPriorityChannelsAllowed();
method public int getPriorityConversationSenders();
method public int getPriorityMessageSenders();
method public int getVisualEffectAmbient();
@@ -42384,7 +42433,7 @@ package android.service.notification {
method @NonNull public android.service.notification.ZenPolicy.Builder allowEvents(boolean);
method @NonNull public android.service.notification.ZenPolicy.Builder allowMedia(boolean);
method @NonNull public android.service.notification.ZenPolicy.Builder allowMessages(int);
- method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy.Builder allowPriorityChannels(boolean);
+ method @NonNull public android.service.notification.ZenPolicy.Builder allowPriorityChannels(boolean);
method @NonNull public android.service.notification.ZenPolicy.Builder allowReminders(boolean);
method @NonNull public android.service.notification.ZenPolicy.Builder allowRepeatCallers(boolean);
method @NonNull public android.service.notification.ZenPolicy.Builder allowSystem(boolean);
@@ -45122,6 +45171,7 @@ package android.telephony {
field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
field public static final String KEY_RTT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_VT_CALL_BOOL = "rtt_upgrade_supported_for_downgraded_vt_call";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL = "satellite_attach_supported_bool";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") public static final String KEY_SATELLITE_CONNECTED_NOTIFICATION_THROTTLE_MILLIS_INT = "satellite_connected_notification_throttle_millis_int";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT = "satellite_connection_hysteresis_sec_int";
field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_DATA_SUPPORT_MODE_INT = "satellite_data_support_mode_int";
field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_DISPLAY_NAME_STRING = "satellite_display_name_string";
@@ -48694,6 +48744,7 @@ package android.telephony.satellite {
@FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") public final class SatelliteManager {
method @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") @RequiresPermission(anyOf={android.Manifest.permission.READ_BASIC_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE, "carrier privileges"}) public void registerStateChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteStateChangeListener);
method @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") @RequiresPermission(anyOf={android.Manifest.permission.READ_BASIC_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE, "carrier privileges"}) public void unregisterStateChangeListener(@NonNull android.telephony.satellite.SatelliteStateChangeListener);
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") public static final String PROPERTY_SATELLITE_DATA_OPTIMIZED = "android.telephony.PROPERTY_SATELLITE_DATA_OPTIMIZED";
}
@FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") public interface SatelliteStateChangeListener {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 76cce7439454..0d5ec199b953 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -7,7 +7,7 @@ package android {
field public static final String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
field public static final String ACCESS_BROADCAST_RESPONSE_STATS = "android.permission.ACCESS_BROADCAST_RESPONSE_STATS";
field public static final String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
- field @FlaggedApi("android.app.contextualsearch.flags.enable_service") public static final String ACCESS_CONTEXTUAL_SEARCH = "android.permission.ACCESS_CONTEXTUAL_SEARCH";
+ field public static final String ACCESS_CONTEXTUAL_SEARCH = "android.permission.ACCESS_CONTEXTUAL_SEARCH";
field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB";
field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
field @FlaggedApi("android.permission.flags.fine_power_monitor_permission") public static final String ACCESS_FINE_POWER_MONITORS = "android.permission.ACCESS_FINE_POWER_MONITORS";
@@ -151,6 +151,8 @@ package android {
field @FlaggedApi("android.content.pm.emergency_install_permission") public static final String EMERGENCY_INSTALL_PACKAGES = "android.permission.EMERGENCY_INSTALL_PACKAGES";
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
field public static final String EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS = "android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String EYE_CALIBRATION = "android.permission.EYE_CALIBRATION";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String FACE_TRACKING_CALIBRATION = "android.permission.FACE_TRACKING_CALIBRATION";
field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String GET_APP_METADATA = "android.permission.GET_APP_METADATA";
@@ -168,6 +170,7 @@ package android {
field public static final String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
field public static final String HDMI_CEC = "android.permission.HDMI_CEC";
field @Deprecated public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String IMPORT_XR_ANCHOR = "android.permission.IMPORT_XR_ANCHOR";
field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String INSTALL_DEPENDENCY_SHARED_LIBRARIES = "android.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES";
field public static final String INSTALL_DPC_PACKAGES = "android.permission.INSTALL_DPC_PACKAGES";
@@ -450,6 +453,7 @@ package android {
field public static final String WRITE_SECURITY_LOG = "android.permission.WRITE_SECURITY_LOG";
field public static final String WRITE_SMS = "android.permission.WRITE_SMS";
field @FlaggedApi("android.provider.user_keys") public static final String WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS = "android.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS";
+ field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_TRACKING_IN_BACKGROUND = "android.permission.XR_TRACKING_IN_BACKGROUND";
}
public static final class Manifest.permission_group {
@@ -2231,7 +2235,7 @@ package android.app.contextualsearch {
field @NonNull public static final android.os.Parcelable.Creator<android.app.contextualsearch.CallbackToken> CREATOR;
}
- public final class ContextualSearchManager {
+ @FlaggedApi("android.app.contextualsearch.flags.self_invocation") public final class ContextualSearchManager {
method @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH) public void startContextualSearch(int);
field public static final String ACTION_LAUNCH_CONTEXTUAL_SEARCH = "android.app.contextualsearch.action.LAUNCH_CONTEXTUAL_SEARCH";
field public static final int ENTRYPOINT_LONG_PRESS_HOME = 2; // 0x2
@@ -2934,6 +2938,14 @@ package android.app.smartspace.uitemplatedata {
}
+package android.app.supervision {
+
+ @FlaggedApi("android.app.supervision.flags.supervision_manager_apis") public class SupervisionManager {
+ method @FlaggedApi("android.app.supervision.flags.supervision_manager_apis") @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isSupervisionEnabled();
+ }
+
+}
+
package android.app.time {
public final class Capabilities {
@@ -3797,6 +3809,7 @@ package android.content {
field public static final String SHARED_CONNECTIVITY_SERVICE = "shared_connectivity";
field public static final String SMARTSPACE_SERVICE = "smartspace";
field public static final String STATS_MANAGER = "stats";
+ field @FlaggedApi("android.app.supervision.flags.supervision_manager_apis") public static final String SUPERVISION_SERVICE = "supervision";
field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
@@ -18580,6 +18593,7 @@ package android.telephony.satellite {
method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatellite(@NonNull java.util.List<android.telephony.satellite.SatelliteSubscriberInfo>, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getAttachRestrictionReasonsForCarrier(int);
+ method @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatelliteDataOptimizedApps();
method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int[] getSatelliteDisallowedReasons();
method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatellitePlmnsForCarrier(int);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9e9e3c2f13c1..975c2c27cb22 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -393,25 +393,25 @@ package android.app {
}
public class NotificationManager {
- method @FlaggedApi("android.app.modes_api") @NonNull public String addAutomaticZenRule(@NonNull android.app.AutomaticZenRule, boolean);
+ method @NonNull public String addAutomaticZenRule(@NonNull android.app.AutomaticZenRule, boolean);
method @FlaggedApi("android.service.notification.notification_classification") public void allowAssistantAdjustment(@NonNull String);
method public void cleanUpCallersAfter(long);
method @FlaggedApi("android.service.notification.notification_classification") public void disallowAssistantAdjustment(@NonNull String);
- method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy getDefaultZenPolicy();
+ method @NonNull public android.service.notification.ZenPolicy getDefaultZenPolicy();
method public android.content.ComponentName getEffectsSuppressor();
method @FlaggedApi("android.service.notification.notification_classification") @NonNull public java.util.Set<java.lang.String> getUnsupportedAdjustmentTypes();
method public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String);
- method @FlaggedApi("android.app.modes_api") public boolean removeAutomaticZenRule(@NonNull String, boolean);
+ method public boolean removeAutomaticZenRule(@NonNull String, boolean);
method @FlaggedApi("android.service.notification.notification_classification") public void setAssistantAdjustmentKeyTypeState(int, boolean);
method @FlaggedApi("android.app.api_rich_ongoing") public void setCanPostPromotedNotifications(@NonNull String, int, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) public void setToastRateLimitingEnabled(boolean);
- method @FlaggedApi("android.app.modes_api") public boolean updateAutomaticZenRule(@NonNull String, @NonNull android.app.AutomaticZenRule, boolean);
+ method public boolean updateAutomaticZenRule(@NonNull String, @NonNull android.app.AutomaticZenRule, boolean);
method public void updateNotificationChannel(@NonNull String, int, @NonNull android.app.NotificationChannel);
}
public static class NotificationManager.Policy implements android.os.Parcelable {
- method @FlaggedApi("android.app.modes_api") public boolean allowPriorityChannels();
+ method public boolean allowPriorityChannels();
}
public final class PendingIntent implements android.os.Parcelable {
@@ -478,8 +478,8 @@ package android.app {
method public void destroy();
method @NonNull public java.util.Set<java.lang.String> getAdoptedShellPermissions();
method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
- method public boolean injectInputEvent(@NonNull android.view.InputEvent, boolean, boolean);
- method public void injectInputEventToInputFilter(@NonNull android.view.InputEvent);
+ method @Deprecated public boolean injectInputEvent(@NonNull android.view.InputEvent, boolean, boolean);
+ method @Deprecated public void injectInputEventToInputFilter(@NonNull android.view.InputEvent);
method public boolean isNodeInCache(@NonNull android.view.accessibility.AccessibilityNodeInfo);
method public void removeOverridePermissionState(int, @NonNull String);
method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
@@ -490,15 +490,15 @@ package android.app {
}
public class UiModeManager {
- method @FlaggedApi("android.app.modes_api") @RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE) public int getAttentionModeThemeOverlay();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE) public int getAttentionModeThemeOverlay();
method public boolean isNightModeLocked();
method public boolean isUiModeLocked();
method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean releaseProjection(int);
method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean requestProjection(int);
- field @FlaggedApi("android.app.modes_api") public static final int MODE_ATTENTION_THEME_OVERLAY_DAY = 1002; // 0x3ea
- field @FlaggedApi("android.app.modes_api") public static final int MODE_ATTENTION_THEME_OVERLAY_NIGHT = 1001; // 0x3e9
- field @FlaggedApi("android.app.modes_api") public static final int MODE_ATTENTION_THEME_OVERLAY_OFF = 1000; // 0x3e8
- field @FlaggedApi("android.app.modes_api") public static final int MODE_ATTENTION_THEME_OVERLAY_UNKNOWN = -1; // 0xffffffff
+ field public static final int MODE_ATTENTION_THEME_OVERLAY_DAY = 1002; // 0x3ea
+ field public static final int MODE_ATTENTION_THEME_OVERLAY_NIGHT = 1001; // 0x3e9
+ field public static final int MODE_ATTENTION_THEME_OVERLAY_OFF = 1000; // 0x3e8
+ field public static final int MODE_ATTENTION_THEME_OVERLAY_UNKNOWN = -1; // 0xffffffff
field public static final int PROJECTION_TYPE_ALL = -1; // 0xffffffff
field public static final int PROJECTION_TYPE_AUTOMOTIVE = 1; // 0x1
field public static final int PROJECTION_TYPE_NONE = 0; // 0x0
@@ -850,6 +850,14 @@ package android.app.prediction {
}
+package android.app.supervision {
+
+ @FlaggedApi("android.app.supervision.flags.supervision_manager_apis") public class SupervisionManager {
+ method public void setSupervisionEnabled(boolean);
+ }
+
+}
+
package android.app.usage {
public class StorageStatsManager {
@@ -1716,7 +1724,7 @@ package android.hardware.display {
}
public final class ColorDisplayManager {
- method @FlaggedApi("android.app.modes_api") @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean isSaturationActivated();
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean isSaturationActivated();
}
public final class DisplayManager {
@@ -3237,16 +3245,16 @@ package android.service.notification {
method @Deprecated public boolean isBound();
}
- @FlaggedApi("android.app.modes_api") public final class ZenDeviceEffects implements android.os.Parcelable {
+ public final class ZenDeviceEffects implements android.os.Parcelable {
method @NonNull public java.util.Set<java.lang.String> getExtraEffects();
}
- @FlaggedApi("android.app.modes_api") public static final class ZenDeviceEffects.Builder {
+ public static final class ZenDeviceEffects.Builder {
method @NonNull public android.service.notification.ZenDeviceEffects.Builder setExtraEffects(@NonNull java.util.Set<java.lang.String>);
}
public final class ZenPolicy implements android.os.Parcelable {
- method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy overwrittenWith(@Nullable android.service.notification.ZenPolicy);
+ method @NonNull public android.service.notification.ZenPolicy overwrittenWith(@Nullable android.service.notification.ZenPolicy);
}
public static final class ZenPolicy.Builder {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 252d23f69400..ee9c64f97382 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -292,13 +292,15 @@ import java.util.function.Consumer;
* to the user, it must be completely restarted and restored to its previous state.</li>
* </ul>
*
- * <p>The following diagram shows the important state paths of an Activity.
+ * <p>The following diagram shows the important state paths of an activity.
* The square rectangles represent callback methods you can implement to
- * perform operations when the Activity moves between states. The colored
- * ovals are major states the Activity can be in.</p>
+ * perform operations when the activity moves between states. The colored
+ * ovals are major states the activity can be in.</p>
*
- * <p><img src="../../../images/activity_lifecycle.png"
- * alt="State diagram for an Android Activity Lifecycle." border="0" /></p>
+ * <p><img class="invert"
+ * style="display: block; margin: auto;"
+ * src="../../../images/activity_lifecycle.png"
+ * alt="State diagram for the Android activity lifecycle." /></p>
*
* <p>There are three key loops you may be interested in monitoring within your
* activity:
@@ -505,7 +507,7 @@ import java.util.function.Consumer;
* changes.</p>
*
* <p>Unless you specify otherwise, a configuration change (such as a change
- * in screen orientation, language, input devices, etc) will cause your
+ * in screen orientation, language, input devices, etc.) will cause your
* current activity to be <em>destroyed</em>, going through the normal activity
* lifecycle process of {@link #onPause},
* {@link #onStop}, and {@link #onDestroy} as appropriate. If the activity
@@ -1838,7 +1840,7 @@ public class Activity extends ContextThemeWrapper
*
* <p>You can call {@link #finish} from within this function, in
* which case onDestroy() will be immediately called after {@link #onCreate} without any of the
- * rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc)
+ * rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc.)
* executing.
*
* <p><em>Derived classes must call through to the super class's
@@ -2132,7 +2134,7 @@ public class Activity extends ContextThemeWrapper
*
* <p>You can call {@link #finish} from within this function, in
* which case {@link #onStop} will be immediately called after {@link #onStart} without the
- * lifecycle transitions in-between ({@link #onResume}, {@link #onPause}, etc) executing.
+ * lifecycle transitions in-between ({@link #onResume}, {@link #onPause}, etc.) executing.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2d7ed46fe64a..f63170aa159d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -104,6 +104,7 @@ import android.content.pm.ServiceInfo;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.content.res.ResourceTimer;
import android.content.res.Resources;
import android.content.res.ResourcesImpl;
import android.content.res.loader.ResourcesLoader;
@@ -5283,6 +5284,7 @@ public final class ActivityThread extends ClientTransactionHandler
Resources.dumpHistory(pw, "");
pw.flush();
+ ResourceTimer.dumpTimers(info.fd.getFileDescriptor(), "-refresh");
if (info.finishCallback != null) {
info.finishCallback.sendResult(null);
}
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
index 3214bd8f01fc..2e8031dd22fe 100644
--- a/core/java/android/app/ApplicationStartInfo.java
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -840,7 +840,9 @@ public final class ApplicationStartInfo implements Parcelable {
* @hide
*/
// LINT.IfChange(write_proto)
- public void writeToProto(ProtoOutputStream proto, long fieldId) throws IOException {
+ public void writeToProto(ProtoOutputStream proto, long fieldId,
+ ByteArrayOutputStream byteArrayOutputStream, ObjectOutputStream objectOutputStream,
+ TypedXmlSerializer typedXmlSerializer) throws IOException {
final long token = proto.start(fieldId);
proto.write(ApplicationStartInfoProto.PID, mPid);
proto.write(ApplicationStartInfoProto.REAL_UID, mRealUid);
@@ -850,38 +852,38 @@ public final class ApplicationStartInfo implements Parcelable {
proto.write(ApplicationStartInfoProto.STARTUP_STATE, mStartupState);
proto.write(ApplicationStartInfoProto.REASON, mReason);
if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) {
- ByteArrayOutputStream timestampsBytes = new ByteArrayOutputStream();
- ObjectOutputStream timestampsOut = new ObjectOutputStream(timestampsBytes);
- TypedXmlSerializer serializer = Xml.resolveSerializer(timestampsOut);
- serializer.startDocument(null, true);
- serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
+ byteArrayOutputStream = new ByteArrayOutputStream();
+ objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
+ typedXmlSerializer = Xml.resolveSerializer(objectOutputStream);
+ typedXmlSerializer.startDocument(null, true);
+ typedXmlSerializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
- serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
- serializer.attributeInt(null, PROTO_SERIALIZER_ATTRIBUTE_KEY,
+ typedXmlSerializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
+ typedXmlSerializer.attributeInt(null, PROTO_SERIALIZER_ATTRIBUTE_KEY,
mStartupTimestampsNs.keyAt(i));
- serializer.attributeLong(null, PROTO_SERIALIZER_ATTRIBUTE_TS,
+ typedXmlSerializer.attributeLong(null, PROTO_SERIALIZER_ATTRIBUTE_TS,
mStartupTimestampsNs.valueAt(i));
- serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
+ typedXmlSerializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
}
- serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
- serializer.endDocument();
+ typedXmlSerializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
+ typedXmlSerializer.endDocument();
proto.write(ApplicationStartInfoProto.STARTUP_TIMESTAMPS,
- timestampsBytes.toByteArray());
- timestampsOut.close();
+ byteArrayOutputStream.toByteArray());
+ objectOutputStream.close();
}
proto.write(ApplicationStartInfoProto.START_TYPE, mStartType);
if (mStartIntent != null) {
- ByteArrayOutputStream intentBytes = new ByteArrayOutputStream();
- ObjectOutputStream intentOut = new ObjectOutputStream(intentBytes);
- TypedXmlSerializer serializer = Xml.resolveSerializer(intentOut);
- serializer.startDocument(null, true);
- serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
- mStartIntent.saveToXml(serializer);
- serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
- serializer.endDocument();
+ byteArrayOutputStream = new ByteArrayOutputStream();
+ objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
+ typedXmlSerializer = Xml.resolveSerializer(objectOutputStream);
+ typedXmlSerializer.startDocument(null, true);
+ typedXmlSerializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
+ mStartIntent.saveToXml(typedXmlSerializer);
+ typedXmlSerializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
+ typedXmlSerializer.endDocument();
proto.write(ApplicationStartInfoProto.START_INTENT,
- intentBytes.toByteArray());
- intentOut.close();
+ byteArrayOutputStream.toByteArray());
+ objectOutputStream.close();
}
proto.write(ApplicationStartInfoProto.LAUNCH_MODE, mLaunchMode);
proto.write(ApplicationStartInfoProto.WAS_FORCE_STOPPED, mWasForceStopped);
@@ -900,7 +902,9 @@ public final class ApplicationStartInfo implements Parcelable {
* @hide
*/
// LINT.IfChange(read_proto)
- public void readFromProto(ProtoInputStream proto, long fieldId)
+ public void readFromProto(ProtoInputStream proto, long fieldId,
+ ByteArrayInputStream byteArrayInputStream, ObjectInputStream objectInputStream,
+ TypedXmlPullParser typedXmlPullParser)
throws IOException, WireTypeMismatchException, ClassNotFoundException {
final long token = proto.start(fieldId);
while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
@@ -927,19 +931,21 @@ public final class ApplicationStartInfo implements Parcelable {
mReason = proto.readInt(ApplicationStartInfoProto.REASON);
break;
case (int) ApplicationStartInfoProto.STARTUP_TIMESTAMPS:
- ByteArrayInputStream timestampsBytes = new ByteArrayInputStream(proto.readBytes(
+ byteArrayInputStream = new ByteArrayInputStream(proto.readBytes(
ApplicationStartInfoProto.STARTUP_TIMESTAMPS));
- ObjectInputStream timestampsIn = new ObjectInputStream(timestampsBytes);
+ objectInputStream = new ObjectInputStream(byteArrayInputStream);
mStartupTimestampsNs = new ArrayMap<Integer, Long>();
try {
- TypedXmlPullParser parser = Xml.resolvePullParser(timestampsIn);
- XmlUtils.beginDocument(parser, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
- int depth = parser.getDepth();
- while (XmlUtils.nextElementWithin(parser, depth)) {
- if (PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP.equals(parser.getName())) {
- int key = parser.getAttributeInt(null,
+ typedXmlPullParser = Xml.resolvePullParser(objectInputStream);
+ XmlUtils.beginDocument(typedXmlPullParser,
+ PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
+ int depth = typedXmlPullParser.getDepth();
+ while (XmlUtils.nextElementWithin(typedXmlPullParser, depth)) {
+ if (PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP.equals(
+ typedXmlPullParser.getName())) {
+ int key = typedXmlPullParser.getAttributeInt(null,
PROTO_SERIALIZER_ATTRIBUTE_KEY);
- long ts = parser.getAttributeLong(null,
+ long ts = typedXmlPullParser.getAttributeLong(null,
PROTO_SERIALIZER_ATTRIBUTE_TS);
mStartupTimestampsNs.put(key, ts);
}
@@ -947,23 +953,24 @@ public final class ApplicationStartInfo implements Parcelable {
} catch (XmlPullParserException e) {
// Timestamps lost
}
- timestampsIn.close();
+ objectInputStream.close();
break;
case (int) ApplicationStartInfoProto.START_TYPE:
mStartType = proto.readInt(ApplicationStartInfoProto.START_TYPE);
break;
case (int) ApplicationStartInfoProto.START_INTENT:
- ByteArrayInputStream intentBytes = new ByteArrayInputStream(proto.readBytes(
+ byteArrayInputStream = new ByteArrayInputStream(proto.readBytes(
ApplicationStartInfoProto.START_INTENT));
- ObjectInputStream intentIn = new ObjectInputStream(intentBytes);
+ objectInputStream = new ObjectInputStream(byteArrayInputStream);
try {
- TypedXmlPullParser parser = Xml.resolvePullParser(intentIn);
- XmlUtils.beginDocument(parser, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
- mStartIntent = Intent.restoreFromXml(parser);
+ typedXmlPullParser = Xml.resolvePullParser(objectInputStream);
+ XmlUtils.beginDocument(typedXmlPullParser,
+ PROTO_SERIALIZER_ATTRIBUTE_INTENT);
+ mStartIntent = Intent.restoreFromXml(typedXmlPullParser);
} catch (XmlPullParserException e) {
// Intent lost
}
- intentIn.close();
+ objectInputStream.close();
break;
case (int) ApplicationStartInfoProto.LAUNCH_MODE:
mLaunchMode = proto.readInt(ApplicationStartInfoProto.LAUNCH_MODE);
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 9d1d9c7b69de..fa977c93113a 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -19,7 +19,6 @@ package android.app;
import static com.android.internal.util.Preconditions.checkArgument;
import android.annotation.DrawableRes;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -52,48 +51,40 @@ public final class AutomaticZenRule implements Parcelable {
* and the value returned if the true type was added in an API level higher than the calling
* app's targetSdk.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int TYPE_UNKNOWN = -1;
/**
* Rule is of a known type, but not one of the specific types.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int TYPE_OTHER = 0;
/**
* The type for rules triggered according to a time-based schedule.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int TYPE_SCHEDULE_TIME = 1;
/**
* The type for rules triggered by calendar events.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int TYPE_SCHEDULE_CALENDAR = 2;
/**
* The type for rules triggered by bedtime/sleeping, like time of day, or snore detection.
*
* <p>Only the 'Wellbeing' app may own rules of this type.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int TYPE_BEDTIME = 3;
/**
* The type for rules triggered by driving detection, like Bluetooth connections or vehicle
* sounds.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int TYPE_DRIVING = 4;
/**
* The type for rules triggered by the user entering an immersive activity, like opening an app
* using {@link WindowInsetsController#hide(int)}.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int TYPE_IMMERSIVE = 5;
/**
* The type for rules that have a {@link ZenPolicy} that implies that the
* device should not make sound and potentially hide some visual effects; may be triggered
* when entering a location where silence is requested, like a theater.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int TYPE_THEATER = 6;
/**
* The type for rules created and managed by a device owner. These rules may not be fully
@@ -101,7 +92,6 @@ public final class AutomaticZenRule implements Parcelable {
*
* <p>Only a 'Device Owner' app may own rules of this type.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int TYPE_MANAGED = 7;
/** @hide */
@@ -127,17 +117,14 @@ public final class AutomaticZenRule implements Parcelable {
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_NAME = 1 << 0;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_INTERRUPTION_FILTER = 1 << 1;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_ICON = 1 << 2;
private boolean enabled;
@@ -149,10 +136,8 @@ public final class AutomaticZenRule implements Parcelable {
private long creationTime;
private ZenPolicy mZenPolicy;
private ZenDeviceEffects mDeviceEffects;
- // TODO: b/310620812 - Remove this once FLAG_MODES_API is inlined.
- private boolean mModified = false;
private String mPkg;
- private int mType = Flags.modesApi() ? TYPE_UNKNOWN : 0;
+ private int mType = TYPE_UNKNOWN;
private int mIconResId;
private String mTriggerDescription;
private boolean mAllowManualInvocation;
@@ -229,8 +214,10 @@ public final class AutomaticZenRule implements Parcelable {
/**
* @hide
+ * @deprecated Do not add new usages; will be removed soon.
*/
- // TODO: b/310620812 - Remove when the flag is inlined (all system callers should use Builder).
+ // TODO: b/368247671 - Remove when modes_ui is inlined (remaining usages are in obsolete tests)
+ @Deprecated
public AutomaticZenRule(String name, ComponentName owner, ComponentName configurationActivity,
Uri conditionId, ZenPolicy policy, int interruptionFilter, boolean enabled,
long creationTime) {
@@ -251,15 +238,12 @@ public final class AutomaticZenRule implements Parcelable {
source.readParcelable(null, android.content.ComponentName.class));
creationTime = source.readLong();
mZenPolicy = source.readParcelable(null, ZenPolicy.class);
- mModified = source.readInt() == ENABLED;
mPkg = source.readString();
- if (Flags.modesApi()) {
- mDeviceEffects = source.readParcelable(null, ZenDeviceEffects.class);
- mAllowManualInvocation = source.readBoolean();
- mIconResId = source.readInt();
- mTriggerDescription = getTrimmedString(source.readString(), MAX_DESC_LENGTH);
- mType = source.readInt();
- }
+ mDeviceEffects = source.readParcelable(null, ZenDeviceEffects.class);
+ mAllowManualInvocation = source.readBoolean();
+ mIconResId = source.readInt();
+ mTriggerDescription = getTrimmedString(source.readString(), MAX_DESC_LENGTH);
+ mType = source.readInt();
}
/**
@@ -306,15 +290,6 @@ public final class AutomaticZenRule implements Parcelable {
}
/**
- * Returns whether this rule's name has been modified by the user.
- * @hide
- */
- // TODO: b/310620812 - Consider removing completely. Seems not be used anywhere except tests.
- public boolean isModified() {
- return mModified;
- }
-
- /**
* Gets the {@link ZenPolicy} applied if {@link #getInterruptionFilter()} is
* {@link NotificationManager#INTERRUPTION_FILTER_PRIORITY}.
*/
@@ -325,7 +300,6 @@ public final class AutomaticZenRule implements Parcelable {
/** Gets the {@link ZenDeviceEffects} of this rule. */
@Nullable
- @FlaggedApi(Flags.FLAG_MODES_API)
public ZenDeviceEffects getDeviceEffects() {
return mDeviceEffects;
}
@@ -378,14 +352,6 @@ public final class AutomaticZenRule implements Parcelable {
}
/**
- * Sets modified state of this rule.
- * @hide
- */
- public void setModified(boolean modified) {
- this.mModified = modified;
- }
-
- /**
* Sets the {@link ZenPolicy} applied if {@link #getInterruptionFilter()} is
* {@link NotificationManager#INTERRUPTION_FILTER_PRIORITY}.
*
@@ -404,7 +370,6 @@ public final class AutomaticZenRule implements Parcelable {
* <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule},
* a {@code null} value here means the previous set of effects is retained.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public void setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) {
mDeviceEffects = deviceEffects;
}
@@ -458,7 +423,6 @@ public final class AutomaticZenRule implements Parcelable {
/**
* Gets the type of the rule.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public @Type int getType() {
return mType;
}
@@ -467,7 +431,6 @@ public final class AutomaticZenRule implements Parcelable {
* Sets the type of the rule.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public void setType(@Type int type) {
mType = checkValidType(type);
}
@@ -476,7 +439,6 @@ public final class AutomaticZenRule implements Parcelable {
* Gets the user visible description of when this rule is active
* (see {@link Condition#STATE_TRUE}).
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public @Nullable String getTriggerDescription() {
return mTriggerDescription;
}
@@ -489,7 +451,6 @@ public final class AutomaticZenRule implements Parcelable {
* "When connected to [Car Name]".
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public void setTriggerDescription(@Nullable String triggerDescription) {
mTriggerDescription = triggerDescription;
}
@@ -497,7 +458,6 @@ public final class AutomaticZenRule implements Parcelable {
/**
* Gets the resource id of the drawable icon for this rule.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public @DrawableRes int getIconResId() {
return mIconResId;
}
@@ -506,7 +466,6 @@ public final class AutomaticZenRule implements Parcelable {
* Sets a resource id of a tintable vector drawable representing the rule in image form.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public void setIconResId(int iconResId) {
mIconResId = iconResId;
}
@@ -515,7 +474,6 @@ public final class AutomaticZenRule implements Parcelable {
* Gets whether this rule can be manually activated by the user even when the triggering
* condition for the rule is not met.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public boolean isManualInvocationAllowed() {
return mAllowManualInvocation;
}
@@ -525,23 +483,18 @@ public final class AutomaticZenRule implements Parcelable {
* condition for the rule is not met.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public void setManualInvocationAllowed(boolean allowManualInvocation) {
mAllowManualInvocation = allowManualInvocation;
}
/** @hide */
- @FlaggedApi(Flags.FLAG_MODES_API)
public void validate() {
- if (Flags.modesApi()) {
- checkValidType(mType);
- if (mDeviceEffects != null) {
- mDeviceEffects.validate();
- }
+ checkValidType(mType);
+ if (mDeviceEffects != null) {
+ mDeviceEffects.validate();
}
}
- @FlaggedApi(Flags.FLAG_MODES_API)
@Type
private static int checkValidType(@Type int type) {
checkArgument(type >= TYPE_UNKNOWN && type <= TYPE_MANAGED,
@@ -571,39 +524,34 @@ public final class AutomaticZenRule implements Parcelable {
dest.writeParcelable(configurationActivity, 0);
dest.writeLong(creationTime);
dest.writeParcelable(mZenPolicy, 0);
- dest.writeInt(mModified ? ENABLED : DISABLED);
dest.writeString(mPkg);
- if (Flags.modesApi()) {
- dest.writeParcelable(mDeviceEffects, 0);
- dest.writeBoolean(mAllowManualInvocation);
- dest.writeInt(mIconResId);
- dest.writeString(mTriggerDescription);
- dest.writeInt(mType);
- }
+ dest.writeParcelable(mDeviceEffects, 0);
+ dest.writeBoolean(mAllowManualInvocation);
+ dest.writeInt(mIconResId);
+ dest.writeString(mTriggerDescription);
+ dest.writeInt(mType);
}
@Override
public String toString() {
- StringBuilder sb = new StringBuilder(AutomaticZenRule.class.getSimpleName()).append('[')
+ return new StringBuilder(AutomaticZenRule.class.getSimpleName())
+ .append('[')
.append("enabled=").append(enabled)
.append(",name=").append(name)
+ .append(",type=").append(mType)
.append(",interruptionFilter=").append(interruptionFilter)
.append(",pkg=").append(mPkg)
.append(",conditionId=").append(conditionId)
.append(",owner=").append(owner)
.append(",configActivity=").append(configurationActivity)
.append(",creationTime=").append(creationTime)
- .append(",mZenPolicy=").append(mZenPolicy);
-
- if (Flags.modesApi()) {
- sb.append(",deviceEffects=").append(mDeviceEffects)
- .append(",allowManualInvocation=").append(mAllowManualInvocation)
- .append(",iconResId=").append(mIconResId)
- .append(",triggerDescription=").append(mTriggerDescription)
- .append(",type=").append(mType);
- }
-
- return sb.append(']').toString();
+ .append(",mZenPolicy=").append(mZenPolicy)
+ .append(",deviceEffects=").append(mDeviceEffects)
+ .append(",allowManualInvocation=").append(mAllowManualInvocation)
+ .append(",iconResId=").append(mIconResId)
+ .append(",triggerDescription=").append(mTriggerDescription)
+ .append(']')
+ .toString();
}
/** @hide */
@@ -626,8 +574,7 @@ public final class AutomaticZenRule implements Parcelable {
if (!(o instanceof AutomaticZenRule)) return false;
if (o == this) return true;
final AutomaticZenRule other = (AutomaticZenRule) o;
- boolean finalEquals = other.enabled == enabled
- && other.mModified == mModified
+ return other.enabled == enabled
&& Objects.equals(other.name, name)
&& other.interruptionFilter == interruptionFilter
&& Objects.equals(other.conditionId, conditionId)
@@ -635,27 +582,19 @@ public final class AutomaticZenRule implements Parcelable {
&& Objects.equals(other.mZenPolicy, mZenPolicy)
&& Objects.equals(other.configurationActivity, configurationActivity)
&& Objects.equals(other.mPkg, mPkg)
- && other.creationTime == creationTime;
- if (Flags.modesApi()) {
- return finalEquals
- && Objects.equals(other.mDeviceEffects, mDeviceEffects)
- && other.mAllowManualInvocation == mAllowManualInvocation
- && other.mIconResId == mIconResId
- && Objects.equals(other.mTriggerDescription, mTriggerDescription)
- && other.mType == mType;
- }
- return finalEquals;
+ && other.creationTime == creationTime
+ && Objects.equals(other.mDeviceEffects, mDeviceEffects)
+ && other.mAllowManualInvocation == mAllowManualInvocation
+ && other.mIconResId == mIconResId
+ && Objects.equals(other.mTriggerDescription, mTriggerDescription)
+ && other.mType == mType;
}
@Override
public int hashCode() {
- if (Flags.modesApi()) {
- return Objects.hash(enabled, name, interruptionFilter, conditionId, owner,
- configurationActivity, mZenPolicy, mDeviceEffects, mModified, creationTime,
- mPkg, mAllowManualInvocation, mIconResId, mTriggerDescription, mType);
- }
return Objects.hash(enabled, name, interruptionFilter, conditionId, owner,
- configurationActivity, mZenPolicy, mModified, creationTime, mPkg);
+ configurationActivity, mZenPolicy, mDeviceEffects, creationTime,
+ mPkg, mAllowManualInvocation, mIconResId, mTriggerDescription, mType);
}
public static final @android.annotation.NonNull Parcelable.Creator<AutomaticZenRule> CREATOR
@@ -705,7 +644,6 @@ public final class AutomaticZenRule implements Parcelable {
return input;
}
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final class Builder {
private String mName;
private ComponentName mOwner;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 6fedcbe50f30..00df7246a300 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -126,6 +126,7 @@ interface INotificationManager
boolean areChannelsBypassingDnd();
ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int uid);
ParceledListSlice getPackagesBypassingDnd(int userId);
+ List<String> getPackagesWithAnyChannels(int userId);
boolean isPackagePaused(String pkg);
void deleteNotificationHistoryItem(String pkg, int uid, long postedTime);
boolean isPermissionFixed(String pkg, int userId);
@@ -224,8 +225,6 @@ interface INotificationManager
ZenPolicy getDefaultZenPolicy();
AutomaticZenRule getAutomaticZenRule(String id);
Map<String, AutomaticZenRule> getAutomaticZenRules();
- // TODO: b/310620812 - Remove getZenRules() when MODES_API is inlined.
- List<ZenModeConfig.ZenRule> getZenRules();
String addAutomaticZenRule(in AutomaticZenRule automaticZenRule, String pkg, boolean fromUser);
boolean updateAutomaticZenRule(String id, in AutomaticZenRule automaticZenRule, boolean fromUser);
boolean removeAutomaticZenRule(String id, boolean fromUser);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0ca4a329fd5a..5dca1c70a2e6 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6002,7 +6002,7 @@ public class Notification implements Parcelable
// HUNS, which use a different layout that already accounts for that). Templates that
// have content that will be displayed under the small icon also use a different margin.
if (Flags.notificationsRedesignTemplates()
- && !p.mHeaderless && !p.mHasContentInLeftMargin) {
+ && !p.mHeaderless && !p.mSkipTopLineAlignment) {
int margin = getContentMarginTop(mContext,
R.dimen.notification_2025_content_margin_top);
contentView.setViewLayoutMargin(R.id.notification_main_column,
@@ -6594,13 +6594,8 @@ public class Notification implements Parcelable
int notifMargin = resources.getDimensionPixelSize(R.dimen.notification_2025_margin);
// Spacing between the text lines, scaling with the font size (originally in sp)
int spacing = resources.getDimensionPixelSize(spacingRes);
-
// Size of the text in the notification top line (originally in sp)
- int[] textSizeAttr = new int[] { android.R.attr.textSize };
- TypedArray typedArray = context.obtainStyledAttributes(
- R.style.TextAppearance_DeviceDefault_Notification_Info, textSizeAttr);
- int textSize = typedArray.getDimensionPixelSize(0 /* index */, -1 /* default */);
- typedArray.recycle();
+ int textSize = resources.getDimensionPixelSize(R.dimen.notification_subtext_size);
// Adding up all the values as pixels
return notifMargin + spacing + textSize;
@@ -9503,7 +9498,7 @@ public class Notification implements Parcelable
.hideLeftIcon(isOneToOne)
.hideRightIcon(hideRightIcons || isOneToOne)
.headerTextSecondary(isHeaderless ? null : conversationTitle)
- .hasContentInLeftMargin(true);
+ .skipTopLineAlignment(true);
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
isConversationLayout
? mBuilder.getConversationLayoutResource()
@@ -14681,7 +14676,7 @@ public class Notification implements Parcelable
Icon mPromotedPicture;
boolean mCallStyleActions;
boolean mAllowTextWithProgress;
- boolean mHasContentInLeftMargin;
+ boolean mSkipTopLineAlignment;
int mTitleViewId;
int mTextViewId;
@Nullable CharSequence mTitle;
@@ -14707,7 +14702,7 @@ public class Notification implements Parcelable
mPromotedPicture = null;
mCallStyleActions = false;
mAllowTextWithProgress = false;
- mHasContentInLeftMargin = false;
+ mSkipTopLineAlignment = false;
mTitleViewId = R.id.title;
mTextViewId = R.id.text;
mTitle = null;
@@ -14774,8 +14769,8 @@ public class Notification implements Parcelable
return this;
}
- public StandardTemplateParams hasContentInLeftMargin(boolean hasContentInLeftMargin) {
- mHasContentInLeftMargin = hasContentInLeftMargin;
+ public StandardTemplateParams skipTopLineAlignment(boolean skipTopLineAlignment) {
+ mSkipTopLineAlignment = skipTopLineAlignment;
return this;
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 00f896deae4b..726999a08322 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -356,7 +356,6 @@ public class NotificationManager {
* a DND component, the rule owner should activate any extra behavior that's part of that mode
* in response to this broadcast.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int AUTOMATIC_RULE_STATUS_ACTIVATED = 4;
/**
@@ -367,7 +366,6 @@ public class NotificationManager {
* longer met) and then {@link Condition#STATE_TRUE} when the trigger criteria is freshly met,
* or when the user re-activates it.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int AUTOMATIC_RULE_STATUS_DEACTIVATED = 5;
/**
@@ -415,7 +413,6 @@ public class NotificationManager {
* <p>This broadcast is only sent to registered receivers and receivers in packages that have
* been granted Notification Policy access (see {@link #isNotificationPolicyAccessGranted()}).
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED =
"android.app.action.CONSOLIDATED_NOTIFICATION_POLICY_CHANGED";
@@ -425,7 +422,6 @@ public class NotificationManager {
* {@link #ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED} containing the new
* {@link Policy} value.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final String EXTRA_NOTIFICATION_POLICY =
"android.app.extra.NOTIFICATION_POLICY";
@@ -1726,9 +1722,8 @@ public class NotificationManager {
* rule management to system settings/uis via
* {@link Settings#ACTION_AUTOMATIC_ZEN_RULE_SETTINGS}.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public boolean areAutomaticZenRulesUserManaged() {
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
PackageManager pm = mContext.getPackageManager();
return !pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
&& !pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
@@ -1748,21 +1743,7 @@ public class NotificationManager {
public Map<String, AutomaticZenRule> getAutomaticZenRules() {
INotificationManager service = service();
try {
- if (Flags.modesApi()) {
- return service.getAutomaticZenRules();
- } else {
- List<ZenModeConfig.ZenRule> rules = service.getZenRules();
- Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
- for (ZenModeConfig.ZenRule rule : rules) {
- AutomaticZenRule azr = new AutomaticZenRule(rule.name, rule.component,
- rule.configurationActivity, rule.conditionId, rule.zenPolicy,
- zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
- rule.creationTime);
- azr.setPackageName(rule.pkg);
- ruleMap.put(rule.id, azr);
- }
- return ruleMap;
- }
+ return service.getAutomaticZenRules();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1804,7 +1785,6 @@ public class NotificationManager {
/** @hide */
@TestApi
- @FlaggedApi(Flags.FLAG_MODES_API)
@NonNull
public String addAutomaticZenRule(@NonNull AutomaticZenRule automaticZenRule,
boolean fromUser) {
@@ -1840,7 +1820,6 @@ public class NotificationManager {
/** @hide */
@TestApi
- @FlaggedApi(Flags.FLAG_MODES_API)
public boolean updateAutomaticZenRule(@NonNull String id,
@NonNull AutomaticZenRule automaticZenRule, boolean fromUser) {
INotificationManager service = service();
@@ -1860,7 +1839,6 @@ public class NotificationManager {
* @param id The id of the rule
* @return the state of the rule.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
@Condition.State
public int getAutomaticZenRuleState(@NonNull String id) {
INotificationManager service = service();
@@ -1935,7 +1913,6 @@ public class NotificationManager {
/** @hide */
@TestApi
- @FlaggedApi(Flags.FLAG_MODES_API)
public boolean removeAutomaticZenRule(@NonNull String id, boolean fromUser) {
INotificationManager service = service();
try {
@@ -2326,7 +2303,6 @@ public class NotificationManager {
* @hide
*/
@TestApi
- @FlaggedApi(Flags.FLAG_MODES_API)
public @NonNull ZenPolicy getDefaultZenPolicy() {
INotificationManager service = service();
try {
@@ -2693,7 +2669,7 @@ public class NotificationManager {
/**
* @hide
*/
- public static final int STATE_CHANNELS_BYPASSING_DND = 1 << 0;
+ public static final int STATE_HAS_PRIORITY_CHANNELS = 1 << 0;
/**
* Whether the policy indicates that even priority channels are NOT permitted to bypass DND.
@@ -2918,7 +2894,7 @@ public class NotificationManager {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder().append("NotificationManager.Policy[")
+ return new StringBuilder().append("NotificationManager.Policy[")
.append("priorityCategories=")
.append(priorityCategoriesToString(priorityCategories))
.append(",priorityCallSenders=")
@@ -2928,24 +2904,19 @@ public class NotificationManager {
.append(",priorityConvSenders=")
.append(conversationSendersToString(priorityConversationSenders))
.append(",suppressedVisualEffects=")
- .append(suppressedEffectsToString(suppressedVisualEffects));
- if (Flags.modesApi()) {
- sb.append(",hasPriorityChannels=");
- } else {
- sb.append(",areChannelsBypassingDnd=");
- }
- sb.append((state == STATE_UNSET
- ? "unset"
- : ((state & STATE_CHANNELS_BYPASSING_DND) != 0)
- ? "true"
- : "false"));
- if (Flags.modesApi()) {
- sb.append(",allowPriorityChannels=")
- .append((state == STATE_UNSET
- ? "unset"
- : (allowPriorityChannels() ? "true" : "false")));
- }
- return sb.append("]").toString();
+ .append(suppressedEffectsToString(suppressedVisualEffects))
+ .append(",hasPriorityChannels=")
+ .append((state == STATE_UNSET
+ ? "unset"
+ : ((state & STATE_HAS_PRIORITY_CHANNELS) != 0)
+ ? "true"
+ : "false"))
+ .append(",allowPriorityChannels=")
+ .append((state == STATE_UNSET
+ ? "unset"
+ : (allowPriorityChannels() ? "true" : "false")))
+ .append("]")
+ .toString();
}
/** @hide */
@@ -3220,7 +3191,6 @@ public class NotificationManager {
}
/** @hide **/
- @FlaggedApi(Flags.FLAG_MODES_API)
@TestApi // so CTS tests can read this state without having to use implementation detail
public boolean allowPriorityChannels() {
if (state == STATE_UNSET) {
@@ -3230,17 +3200,15 @@ public class NotificationManager {
}
/** @hide */
- @FlaggedApi(Flags.FLAG_MODES_API)
public boolean hasPriorityChannels() {
- return (state & STATE_CHANNELS_BYPASSING_DND) != 0;
+ return (state & STATE_HAS_PRIORITY_CHANNELS) != 0;
}
/** @hide **/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static int policyState(boolean hasPriorityChannels, boolean allowPriorityChannels) {
int state = 0;
if (hasPriorityChannels) {
- state |= STATE_CHANNELS_BYPASSING_DND;
+ state |= STATE_HAS_PRIORITY_CHANNELS;
}
if (!allowPriorityChannels) {
state |= STATE_PRIORITY_CHANNELS_BLOCKED;
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 7b63ab80964d..464bcc025d92 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -956,10 +956,9 @@ public final class UiAutomation {
* <p>
* <strong>Note:</strong> It is caller's responsibility to recycle the event.
* </p>
- *
- * @param event The event to inject.
- * @param sync Whether to inject the event synchronously.
- * @return Whether event injection succeeded.
+ * @param event the event to inject
+ * @param sync whether to inject the event synchronously
+ * @return {@code true} if event injection succeeded
*/
public boolean injectInputEvent(InputEvent event, boolean sync) {
return injectInputEvent(event, sync, true /* waitForAnimations */);
@@ -972,15 +971,21 @@ public final class UiAutomation {
* <strong>Note:</strong> It is caller's responsibility to recycle the event.
* </p>
*
- * @param event The event to inject.
- * @param sync Whether to inject the event synchronously.
- * @param waitForAnimations Whether to wait for all window container animations and surface
- * operations to complete.
- * @return Whether event injection succeeded.
+ * @param event the event to inject
+ * @param sync whether to inject the event synchronously.
+ * @param waitForAnimations whether to wait for all window container animations and surface
+ * operations to complete
+ * @return {@code true} if event injection succeeded
*
+ * @deprecated for CTS tests prefer inject input events using uinput
+ * (com.android.cts.input.UinputDevice) or hid devices (com.android.cts.input.HidDevice).
+ * Alternatively, InjectInputInProcess (com.android.cts.input.InjectInputProcess) can be used
+ * for in-process injection.
* @hide
*/
@TestApi
+ @Deprecated // Deprecated for CTS tests
+ @SuppressLint("UnflaggedApi") // @FlaggedApi breaks previously released @TestApi, b/395889250
public boolean injectInputEvent(@NonNull InputEvent event, boolean sync,
boolean waitForAnimations) {
try {
@@ -1003,9 +1008,15 @@ public final class UiAutomation {
* Events injected to the input subsystem using the standard {@link #injectInputEvent} method
* skip the accessibility input filter to avoid feedback loops.
*
+ * @deprecated for CTS tests prefer inject input events using uinput
+ * (com.android.cts.input.UinputDevice) or hid devices (com.android.cts.input.HidDevice).
+ * Alternatively, InjectInputInProcess (com.android.cts.input.InjectInputProcess) can be used
+ * for in-process injection.
* @hide
*/
@TestApi
+ @Deprecated
+ @SuppressLint("UnflaggedApi") // @FlaggedApi breaks previously released @TestApi, b/395889250
public void injectInputEventToInputFilter(@NonNull InputEvent event) {
try {
mUiAutomationConnection.injectInputEventToInputFilter(event);
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index f6c789d51aee..33466dd79be1 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -312,7 +312,6 @@ public class UiModeManager {
* #getAttentionModeThemeOverlay()}: Keeps night mode as set by {@link #setNightMode(int)}.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
@TestApi
public static final int MODE_ATTENTION_THEME_OVERLAY_OFF = 1000;
@@ -321,7 +320,6 @@ public class UiModeManager {
* #getAttentionModeThemeOverlay()}: Maintains night mode always on.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
@TestApi
public static final int MODE_ATTENTION_THEME_OVERLAY_NIGHT = 1001;
@@ -330,7 +328,6 @@ public class UiModeManager {
* #getAttentionModeThemeOverlay()}: Maintains night mode always off (Light).
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
@TestApi
public static final int MODE_ATTENTION_THEME_OVERLAY_DAY = 1002;
@@ -338,7 +335,6 @@ public class UiModeManager {
* Constant for {@link #getAttentionModeThemeOverlay()}: Error communication with server.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
@TestApi
public static final int MODE_ATTENTION_THEME_OVERLAY_UNKNOWN = -1;
@@ -940,7 +936,6 @@ public class UiModeManager {
* {@code AttentionModeThemeOverlayType}.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
public void setAttentionModeThemeOverlay(
@AttentionModeThemeOverlayType int attentionModeThemeOverlayType) {
@@ -967,7 +962,6 @@ public class UiModeManager {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
@TestApi
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
public @AttentionModeThemeOverlayReturnType int getAttentionModeThemeOverlay() {
diff --git a/core/java/android/app/backup/BackupRestoreEventLogger.java b/core/java/android/app/backup/BackupRestoreEventLogger.java
index 112c5fd808ef..8bde3a5f2efa 100644
--- a/core/java/android/app/backup/BackupRestoreEventLogger.java
+++ b/core/java/android/app/backup/BackupRestoreEventLogger.java
@@ -34,9 +34,11 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* Class to log B&R stats for each data type that is backed up and restored by the calling app.
@@ -325,6 +327,21 @@ public final class BackupRestoreEventLogger {
}
}
+ /** @hide */
+ public static String toString(DataTypeResult result) {
+ Objects.requireNonNull(result, "result cannot be null");
+ StringBuilder string = new StringBuilder("type=").append(result.mDataType)
+ .append(", successCount=").append(result.mSuccessCount)
+ .append(", failCount=").append(result.mFailCount);
+ if (!result.mErrors.isEmpty()) {
+ string.append(", errors=").append(result.mErrors);
+ }
+ if (result.mMetadataHash != null) {
+ string.append(", metadataHash=").append(Arrays.toString(result.mMetadataHash));
+ }
+ return string.toString();
+ }
+
/**
* Encapsulate logging results for a single data type.
*/
diff --git a/core/java/android/app/contextualsearch/ContextualSearchManager.java b/core/java/android/app/contextualsearch/ContextualSearchManager.java
index 2ce431dcb32d..4e5fa6bac951 100644
--- a/core/java/android/app/contextualsearch/ContextualSearchManager.java
+++ b/core/java/android/app/contextualsearch/ContextualSearchManager.java
@@ -32,6 +32,9 @@ import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
/**
* {@link ContextualSearchManager} is a system service to facilitate contextual search experience on
@@ -39,10 +42,8 @@ import java.lang.annotation.RetentionPolicy;
* <p>
* This class lets a caller start contextual search by calling {@link #startContextualSearch}
* method.
- *
- * @hide
*/
-@SystemApi
+@FlaggedApi(Flags.FLAG_SELF_INVOCATION)
public final class ContextualSearchManager {
/**
@@ -50,7 +51,9 @@ public final class ContextualSearchManager {
* Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH.
*
* @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH
+ * @hide
*/
+ @SystemApi
public static final String EXTRA_ENTRYPOINT =
"android.app.contextualsearch.extra.ENTRYPOINT";
@@ -60,7 +63,9 @@ public final class ContextualSearchManager {
* Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH.
*
* @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH
+ * @hide
*/
+ @SystemApi
public static final String EXTRA_FLAG_SECURE_FOUND =
"android.app.contextualsearch.extra.FLAG_SECURE_FOUND";
@@ -69,7 +74,9 @@ public final class ContextualSearchManager {
* Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH.
*
* @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH
+ * @hide
*/
+ @SystemApi
public static final String EXTRA_SCREENSHOT =
"android.app.contextualsearch.extra.SCREENSHOT";
@@ -79,7 +86,9 @@ public final class ContextualSearchManager {
* Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH.
*
* @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH
+ * @hide
*/
+ @SystemApi
public static final String EXTRA_IS_MANAGED_PROFILE_VISIBLE =
"android.app.contextualsearch.extra.IS_MANAGED_PROFILE_VISIBLE";
@@ -89,7 +98,9 @@ public final class ContextualSearchManager {
* Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH.
*
* @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH
+ * @hide
*/
+ @SystemApi
public static final String EXTRA_VISIBLE_PACKAGE_NAMES =
"android.app.contextualsearch.extra.VISIBLE_PACKAGE_NAMES";
@@ -98,10 +109,9 @@ public final class ContextualSearchManager {
* {@link SystemClock#uptimeMillis()}.
* Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH.
*
- * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH
- *
* TODO: un-hide in W
*
+ * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH
* @hide
*/
public static final String EXTRA_INVOCATION_TIME_MS =
@@ -113,7 +123,9 @@ public final class ContextualSearchManager {
* Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH.
*
* @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH
+ * @hide
*/
+ @SystemApi
public static final String EXTRA_TOKEN = "android.app.contextualsearch.extra.TOKEN";
/**
@@ -132,7 +144,10 @@ public final class ContextualSearchManager {
* experience must add this intent filter action to the activity it wants to be launched.
* <br>
* <b>Note</b> This activity must not be exported.
+ *
+ * @hide
*/
+ @SystemApi
public static final String ACTION_LAUNCH_CONTEXTUAL_SEARCH =
"android.app.contextualsearch.action.LAUNCH_CONTEXTUAL_SEARCH";
@@ -144,23 +159,63 @@ public final class ContextualSearchManager {
public static final String FEATURE_CONTEXTUAL_SEARCH =
"com.google.android.feature.CONTEXTUAL_SEARCH";
- /** Entrypoint to be used when a user long presses on the nav handle. */
+ /**
+ * Entrypoint to be used when a user long presses on the nav handle.
+ *
+ * @hide
+ */
+ @SystemApi
public static final int ENTRYPOINT_LONG_PRESS_NAV_HANDLE = 1;
- /** Entrypoint to be used when a user long presses on the home button. */
+
+ /** Entrypoint to be used when a user long presses on the home button.
+ *
+ * @hide
+ */
+ @SystemApi
public static final int ENTRYPOINT_LONG_PRESS_HOME = 2;
- /** Entrypoint to be used when a user long presses on the overview button. */
+
+ /** Entrypoint to be used when a user long presses on the overview button.
+ *
+ * @hide
+ */
+ @SystemApi
public static final int ENTRYPOINT_LONG_PRESS_OVERVIEW = 3;
- /** Entrypoint to be used when a user presses the action button in overview. */
+
+ /**
+ * Entrypoint to be used when a user presses the action button in overview.
+ *
+ * @hide
+ */
+ @SystemApi
public static final int ENTRYPOINT_OVERVIEW_ACTION = 4;
- /** Entrypoint to be used when a user presses the context menu button in overview. */
+
+ /**
+ * Entrypoint to be used when a user presses the context menu button in overview.
+ *
+ * @hide
+ */
+ @SystemApi
public static final int ENTRYPOINT_OVERVIEW_MENU = 5;
- /** Entrypoint to be used by system actions like TalkBack, Accessibility etc. */
+
+ /**
+ * Entrypoint to be used by system actions like TalkBack, Accessibility etc.
+ *
+ * @hide
+ */
+ @SystemApi
public static final int ENTRYPOINT_SYSTEM_ACTION = 9;
- /** Entrypoint to be used when a user long presses on the meta key. */
+
+ /**
+ * Entrypoint to be used when a user long presses on the meta key.
+ *
+ * @hide
+ */
+ @SystemApi
public static final int ENTRYPOINT_LONG_PRESS_META = 10;
+
/**
* The {@link Entrypoint} annotation is used to standardize the entrypoints supported by
- * {@link #startContextualSearch} method.
+ * {@link #startContextualSearch(int entrypoint)} method.
*
* @hide
*/
@@ -174,8 +229,18 @@ public final class ContextualSearchManager {
ENTRYPOINT_LONG_PRESS_META
})
@Retention(RetentionPolicy.SOURCE)
- public @interface Entrypoint {
- }
+ public @interface Entrypoint {}
+
+ private static final Set<Integer> VALID_ENTRYPOINT_VALUES = new HashSet<>(Arrays.asList(
+ ENTRYPOINT_LONG_PRESS_NAV_HANDLE,
+ ENTRYPOINT_LONG_PRESS_HOME,
+ ENTRYPOINT_LONG_PRESS_OVERVIEW,
+ ENTRYPOINT_OVERVIEW_ACTION,
+ ENTRYPOINT_OVERVIEW_MENU,
+ ENTRYPOINT_SYSTEM_ACTION,
+ ENTRYPOINT_LONG_PRESS_META
+ ));
+
private static final String TAG = ContextualSearchManager.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -189,7 +254,7 @@ public final class ContextualSearchManager {
}
/**
- * Used to start contextual search.
+ * Used to start contextual search for a given system entrypoint.
* <p>
* When {@link #startContextualSearch} is called, the system server does the following:
* <ul>
@@ -202,9 +267,15 @@ public final class ContextualSearchManager {
* </p>
*
* @param entrypoint the invocation entrypoint
+ *
+ * @hide
*/
@RequiresPermission(ACCESS_CONTEXTUAL_SEARCH)
+ @SystemApi
public void startContextualSearch(@Entrypoint int entrypoint) {
+ if (!VALID_ENTRYPOINT_VALUES.contains(entrypoint)) {
+ throw new IllegalArgumentException("Invalid entrypoint: " + entrypoint);
+ }
if (DEBUG) Log.d(TAG, "startContextualSearch for entrypoint: " + entrypoint);
try {
mService.startContextualSearch(entrypoint);
@@ -213,4 +284,22 @@ public final class ContextualSearchManager {
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Used to start contextual search from within an app.
+ *
+ * <p>System apps should use the available System APIs rather than this method.
+ *
+ * @throws SecurityException if the caller does not have a foreground Activity.
+ */
+ @FlaggedApi(Flags.FLAG_SELF_INVOCATION)
+ public void startContextualSearch() {
+ if (DEBUG) Log.d(TAG, "startContextualSearch from app");
+ try {
+ mService.startContextualSearchForForegroundApp();
+ } catch (RemoteException e) {
+ if (DEBUG) Log.d(TAG, "Failed to startContextualSearch", e);
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/contextualsearch/IContextualSearchManager.aidl b/core/java/android/app/contextualsearch/IContextualSearchManager.aidl
index 9b0b8b775971..8789daab3afe 100644
--- a/core/java/android/app/contextualsearch/IContextualSearchManager.aidl
+++ b/core/java/android/app/contextualsearch/IContextualSearchManager.aidl
@@ -4,7 +4,8 @@ import android.app.contextualsearch.IContextualSearchCallback;
/**
* @hide
*/
-oneway interface IContextualSearchManager {
- void startContextualSearch(int entrypoint);
- void getContextualSearchState(in IBinder token, in IContextualSearchCallback callback);
+interface IContextualSearchManager {
+ void startContextualSearchForForegroundApp();
+ oneway void startContextualSearch(int entrypoint);
+ oneway void getContextualSearchState(in IBinder token, in IContextualSearchCallback callback);
}
diff --git a/core/java/android/app/contextualsearch/flags.aconfig b/core/java/android/app/contextualsearch/flags.aconfig
index d81ec1e8b883..bc1f7cea7fce 100644
--- a/core/java/android/app/contextualsearch/flags.aconfig
+++ b/core/java/android/app/contextualsearch/flags.aconfig
@@ -39,3 +39,11 @@ flag {
description: "Add audio playing status to the contextual search invocation intent."
bug: "372935419"
}
+
+flag {
+ name: "self_invocation"
+ namespace: "sysui_integrations"
+ description: "Enable apps to self-invoke Contextual Search."
+ bug: "368653769"
+ is_exported: true
+}
diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java
index b4c293eeb695..7718d159896e 100644
--- a/core/java/android/app/jank/JankDataProcessor.java
+++ b/core/java/android/app/jank/JankDataProcessor.java
@@ -34,11 +34,13 @@ import java.util.List;
/**
* This class is responsible for associating frames received from SurfaceFlinger to active widget
* states and logging those states back to the platform.
+ *
* @hide
*/
@FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
public class JankDataProcessor {
-
+ private static final String TAG = "JankDataProcessor";
+ private static final boolean DEBUG_LOGGING = false;
private static final int MAX_IN_MEMORY_STATS = 25;
private static final int LOG_BATCH_FREQUENCY = 50;
private int mCurrentBatchCount = 0;
@@ -54,9 +56,10 @@ public class JankDataProcessor {
/**
* Called once per batch of JankData.
- * @param jankData data received from SurfaceFlinger to be processed
+ *
+ * @param jankData data received from SurfaceFlinger to be processed
* @param activityName name of the activity that is tracking jank metrics.
- * @param appUid the uid of the app.
+ * @param appUid the uid of the app.
*/
public void processJankData(List<JankData> jankData, String activityName, int appUid) {
// add all the previous and active states to the pending states list.
@@ -211,8 +214,6 @@ public class JankDataProcessor {
* clear any pending widget states.
*/
public void logMetricCounts() {
- //TODO b/374607503 when api changes are in add enum mapping for category and state.
-
try {
mPendingJankStats.values().forEach(stat -> {
FrameworkStatsLog.write(
@@ -221,15 +222,16 @@ public class JankDataProcessor {
/*activity name*/ stat.getActivityName(),
/*widget id*/ stat.getWidgetId(),
/*refresh rate*/ stat.getRefreshRate(),
- /*widget category*/ 0,
- /*widget state*/ 0,
+ /*widget category*/ widgetCategoryToInt(stat.getWidgetCategory()),
+ /*widget state*/ widgetStateToInt(stat.getWidgetState()),
/*total frames*/ stat.getTotalFrames(),
/*janky frames*/ stat.getJankyFrames(),
- /*histogram*/ stat.mFrameOverrunBuckets);
+ /*histogram*/ stat.getFrameOverrunBuckets());
Log.d(stat.mActivityName, stat.toString());
// return the pending stat to the pool it will be reset the next time its
// used.
mPendingJankStatsPool.release(stat);
+
}
);
// All stats have been recorded and added back to the pool for reuse, clear the pending
@@ -241,6 +243,96 @@ public class JankDataProcessor {
}
}
+ private int widgetCategoryToInt(String widgetCategory) {
+ switch (widgetCategory) {
+ case AppJankStats.WIDGET_CATEGORY_SCROLL -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__SCROLLING;
+ }
+ case AppJankStats.WIDGET_CATEGORY_ANIMATION -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__ANIMATION;
+ }
+ case AppJankStats.WIDGET_CATEGORY_MEDIA -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__MEDIA;
+ }
+ case AppJankStats.WIDGET_CATEGORY_NAVIGATION -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__NAVIGATION;
+ }
+ case AppJankStats.WIDGET_CATEGORY_KEYBOARD -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__KEYBOARD;
+ }
+ case AppJankStats.WIDGET_CATEGORY_OTHER -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__OTHER;
+ }
+ default -> {
+ if (DEBUG_LOGGING) {
+ Log.d(TAG, "Default Category Logged: "
+ + AppJankStats.WIDGET_CATEGORY_UNSPECIFIED);
+ }
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__WIDGET_CATEGORY_UNSPECIFIED;
+ }
+ }
+ }
+
+ private int widgetStateToInt(String widgetState) {
+ switch (widgetState) {
+ case AppJankStats.WIDGET_STATE_NONE -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__NONE;
+ }
+ case AppJankStats.WIDGET_STATE_SCROLLING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__SCROLLING;
+ }
+ case AppJankStats.WIDGET_STATE_FLINGING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__FLINGING;
+ }
+ case AppJankStats.WIDGET_STATE_SWIPING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__SWIPING;
+ }
+ case AppJankStats.WIDGET_STATE_DRAGGING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__DRAGGING;
+ }
+ case AppJankStats.WIDGET_STATE_ZOOMING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__ZOOMING;
+ }
+ case AppJankStats.WIDGET_STATE_ANIMATING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__ANIMATING;
+ }
+ case AppJankStats.WIDGET_STATE_PLAYBACK -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__PLAYBACK;
+ }
+ case AppJankStats.WIDGET_STATE_TAPPING -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__TAPPING;
+ }
+ case AppJankStats.WIDGET_STATE_PREDICTIVE_BACK -> {
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__PREDICTIVE_BACK;
+ }
+ default -> {
+ if (DEBUG_LOGGING) {
+ Log.d(TAG, "Default State Logged: "
+ + AppJankStats.WIDGET_STATE_UNSPECIFIED);
+ }
+ return FrameworkStatsLog
+ .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__WIDGET_STATE_UNSPECIFIED;
+ }
+ }
+ }
+
public static final class PendingJankStat {
private static final int NANOS_PER_MS = 1000000;
public long processedVsyncId = -1;
@@ -268,7 +360,7 @@ public class JankDataProcessor {
private int mRefreshRate;
- private static final int[] sFrameOverrunHistogramBounds = {
+ private static final int[] sFrameOverrunHistogramBounds = {
Integer.MIN_VALUE, -200, -150, -100, -90, -80, -70, -60, -50, -40, -30, -25, -20,
-18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 25,
30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000,
@@ -279,6 +371,7 @@ public class JankDataProcessor {
// Histogram of frame duration overruns encoded in predetermined buckets.
public PendingJankStat() {
}
+
public long getProcessedVsyncId() {
return processedVsyncId;
}
@@ -422,4 +515,4 @@ public class JankDataProcessor {
}
}
-}
+} \ No newline at end of file
diff --git a/core/java/android/app/jank/JankTracker.java b/core/java/android/app/jank/JankTracker.java
index a04f96a9f6e3..9c85b09f6be3 100644
--- a/core/java/android/app/jank/JankTracker.java
+++ b/core/java/android/app/jank/JankTracker.java
@@ -20,6 +20,7 @@ import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.os.Handler;
import android.os.HandlerThread;
+import android.util.Log;
import android.view.AttachedSurfaceControl;
import android.view.Choreographer;
import android.view.SurfaceControl;
@@ -30,16 +31,22 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
/**
* This class is responsible for registering callbacks that will receive JankData batches.
* It handles managing the background thread that JankData will be processed on. As well as acting
* as an intermediary between widgets and the state tracker, routing state changes to the tracker.
+ *
* @hide
*/
@FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
public class JankTracker {
-
+ private static final boolean DEBUG = false;
+ private static final String DEBUG_KEY = "JANKTRACKER";
+ // How long to delay the JankData listener registration.
+ //TODO b/394956095 see if this can be reduced or eliminated.
+ private static final int REGISTRATION_DELAY_MS = 1000;
// Tracks states reported by widgets.
private StateTracker mStateTracker;
// Processes JankData batches and associates frames to widget states.
@@ -49,9 +56,6 @@ public class JankTracker {
private HandlerThread mHandlerThread = new HandlerThread("AppJankTracker");
private Handler mHandler = null;
- // Needed so we know when the view is attached to a window.
- private ViewTreeObserver mViewTreeObserver;
-
// Handle to a registered OnJankData listener.
private SurfaceControl.OnJankDataListenerRegistration mJankDataListenerRegistration;
@@ -76,6 +80,40 @@ public class JankTracker {
*/
private boolean mListenersRegistered = false;
+ @FlaggedApi(com.android.window.flags.Flags.FLAG_JANK_API)
+ private final SurfaceControl.OnJankDataListener mJankDataListener =
+ new SurfaceControl.OnJankDataListener() {
+ @Override
+ public void onJankDataAvailable(
+ @androidx.annotation.NonNull List<SurfaceControl.JankData> jankData) {
+ if (mJankDataProcessor == null) return;
+ mJankDataProcessor.processJankData(jankData, mActivityName, mAppUid);
+ }
+ };
+
+ private final ViewTreeObserver.OnWindowAttachListener mOnWindowAttachListener =
+ new ViewTreeObserver.OnWindowAttachListener() {
+ @Override
+ public void onWindowAttached() {
+ getHandler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mDecorView.getViewTreeObserver()
+ .removeOnWindowAttachListener(mOnWindowAttachListener);
+ registerForJankData();
+ }
+ }, REGISTRATION_DELAY_MS);
+ }
+
+ // Leave this empty. Only need to know when the DecorView is attached to the Window
+ // in order to get a handle to AttachedSurfaceControl. There is no need to tie
+ // anything to when the view is detached as all un-registration code is tied to
+ // the lifecycle of the enclosing activity.
+ @Override
+ public void onWindowDetached() {
+
+ }
+ };
public JankTracker(Choreographer choreographer, View decorView) {
mStateTracker = new StateTracker(choreographer);
@@ -108,9 +146,10 @@ public class JankTracker {
/**
* Will add the widget category, id and state as a UI state to associate frames to it.
+ *
* @param widgetCategory preselected general widget category
- * @param widgetId developer defined widget id if available.
- * @param widgetState the current active widget state.
+ * @param widgetId developer defined widget id if available.
+ * @param widgetState the current active widget state.
*/
public void addUiState(String widgetCategory, String widgetId, String widgetState) {
if (!shouldTrack()) return;
@@ -121,9 +160,10 @@ public class JankTracker {
/**
* Will remove the widget category, id and state as a ui state and no longer attribute frames
* to it.
+ *
* @param widgetCategory preselected general widget category
- * @param widgetId developer defined widget id if available.
- * @param widgetState no longer active widget state.
+ * @param widgetId developer defined widget id if available.
+ * @param widgetState no longer active widget state.
*/
public void removeUiState(String widgetCategory, String widgetId, String widgetState) {
if (!shouldTrack()) return;
@@ -133,10 +173,11 @@ public class JankTracker {
/**
* Call to update a jank state to a different state.
+ *
* @param widgetCategory preselected general widget category.
- * @param widgetId developer defined widget id if available.
- * @param currentState current state of the widget.
- * @param nextState the state the widget will be in.
+ * @param widgetId developer defined widget id if available.
+ * @param currentState current state of the widget.
+ * @param nextState the state the widget will be in.
*/
public void updateUiState(String widgetCategory, String widgetId, String currentState,
String nextState) {
@@ -150,10 +191,11 @@ public class JankTracker {
*/
public void enableAppJankTracking() {
// Add the activity as a state, this will ensure we track frames to the activity without the
- // need of a decorated widget to be used.
+ // need for a decorated widget to be used.
// TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged.
mStateTracker.putState("NONE", mActivityName, "NONE");
mTrackingEnabled = true;
+ registerForJankData();
}
/**
@@ -163,10 +205,12 @@ public class JankTracker {
mTrackingEnabled = false;
// TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged.
mStateTracker.removeState("NONE", mActivityName, "NONE");
+ unregisterForJankData();
}
/**
* Retrieve all pending widget states, this is intended for testing purposes only.
+ *
* @param stateDataList the ArrayList that will be populated with the pending states.
*/
@VisibleForTesting
@@ -190,16 +234,35 @@ public class JankTracker {
@VisibleForTesting
public void forceListenerRegistration() {
mSurfaceControl = mDecorView.getRootSurfaceControl();
- registerForJankData();
- // TODO b/376116199 Check if registration is good.
- mListenersRegistered = true;
+ registerJankDataListener();
+ }
+
+ private void unregisterForJankData() {
+ if (mJankDataListenerRegistration == null) return;
+
+ if (com.android.window.flags.Flags.jankApi()) {
+ mJankDataListenerRegistration.release();
+ }
+ mJankDataListenerRegistration = null;
+ mListenersRegistered = false;
}
private void registerForJankData() {
- if (mSurfaceControl == null) return;
- /*
- TODO b/376115668 Register for JankData batches from new JankTracking API
- */
+ if (mDecorView == null) return;
+
+ mSurfaceControl = mDecorView.getRootSurfaceControl();
+
+ if (mSurfaceControl == null || mListenersRegistered) return;
+
+ // Wait a short time before registering the listener. During development it was observed
+ // that if a listener is registered too quickly after a hot or warm start no data is
+ // received b/394956095.
+ getHandler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ registerJankDataListener();
+ }
+ }, REGISTRATION_DELAY_MS);
}
/**
@@ -218,23 +281,30 @@ public class JankTracker {
*/
private void registerWindowListeners() {
if (mDecorView == null) return;
- mViewTreeObserver = mDecorView.getViewTreeObserver();
- mViewTreeObserver.addOnWindowAttachListener(new ViewTreeObserver.OnWindowAttachListener() {
- @Override
- public void onWindowAttached() {
- getHandler().postDelayed(new Runnable() {
- @Override
- public void run() {
- forceListenerRegistration();
- }
- }, 1000);
+ mDecorView.getViewTreeObserver().addOnWindowAttachListener(mOnWindowAttachListener);
+ }
+
+ private void registerJankDataListener() {
+ if (mSurfaceControl == null) {
+ if (DEBUG) {
+ Log.d(DEBUG_KEY, "SurfaceControl is Null");
}
+ return;
+ }
- @Override
- public void onWindowDetached() {
- // TODO b/376116199 do we un-register the callback or just not process the data.
+ if (com.android.window.flags.Flags.jankApi()) {
+ mJankDataListenerRegistration = mSurfaceControl.registerOnJankDataListener(
+ mHandlerThread.getThreadExecutor(), mJankDataListener);
+
+ if (mJankDataListenerRegistration
+ == SurfaceControl.OnJankDataListenerRegistration.NONE) {
+ if (DEBUG) {
+ Log.d(DEBUG_KEY, "OnJankDataListenerRegistration is assigned NONE");
+ }
+ return;
}
- });
+ mListenersRegistered = true;
+ }
}
private Handler getHandler() {
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index a10b6ff39a37..8e6b88c66408 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -26,6 +26,7 @@ flag {
bug: "378660052"
}
+# Flag for finalized API: In Nextfood but exported (and therefore must stay).
flag {
name: "modes_api"
is_exported: true
@@ -82,6 +83,13 @@ flag {
}
flag {
+ name: "modes_cleanup_implicit"
+ namespace: "systemui"
+ description: "Deletes implicit modes if never customized and not used for some time. Depends on MODES_UI"
+ bug: "394087495"
+}
+
+flag {
name: "api_tvextender"
is_exported: true
namespace: "systemui"
@@ -308,10 +316,20 @@ flag {
}
flag {
+ name: "nm_binder_perf_get_apps_with_channels"
+ namespace: "systemui"
+ description: "Use a single binder call to get the set of apps with channels for a user"
+ bug: "362981561"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "no_sbnholder"
namespace: "systemui"
description: "removes sbnholder from NLS"
- bug: "362981561"
+ bug: "378128805"
}
flag {
diff --git a/core/java/android/app/supervision/ISupervisionManager.aidl b/core/java/android/app/supervision/ISupervisionManager.aidl
index e583302e4d3b..2f67a8abcd17 100644
--- a/core/java/android/app/supervision/ISupervisionManager.aidl
+++ b/core/java/android/app/supervision/ISupervisionManager.aidl
@@ -16,11 +16,14 @@
package android.app.supervision;
+import android.content.Intent;
+
/**
* Internal IPC interface to the supervision service.
* {@hide}
*/
interface ISupervisionManager {
+ Intent createConfirmSupervisionCredentialsIntent();
boolean isSupervisionEnabledForUser(int userId);
void setSupervisionEnabledForUser(int userId, boolean enabled);
String getActiveSupervisionAppPackage(int userId);
diff --git a/core/java/android/app/supervision/SupervisionManager.java b/core/java/android/app/supervision/SupervisionManager.java
index d30705536045..0270edf080a9 100644
--- a/core/java/android/app/supervision/SupervisionManager.java
+++ b/core/java/android/app/supervision/SupervisionManager.java
@@ -16,13 +16,22 @@
package android.app.supervision;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.MANAGE_USERS;
+import static android.Manifest.permission.QUERY_USERS;
+
+import android.annotation.FlaggedApi;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
+import android.app.supervision.flags.Flags;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.content.Intent;
import android.os.RemoteException;
/**
@@ -31,6 +40,8 @@ import android.os.RemoteException;
* @hide
*/
@SystemService(Context.SUPERVISION_SERVICE)
+@SystemApi
+@FlaggedApi(Flags.FLAG_SUPERVISION_MANAGER_APIS)
public class SupervisionManager {
private final Context mContext;
@Nullable private final ISupervisionManager mService;
@@ -47,7 +58,8 @@ public class SupervisionManager {
*
* @hide
*/
- public static final String ACTION_ENABLE_SUPERVISION = "android.app.action.ENABLE_SUPERVISION";
+ public static final String ACTION_ENABLE_SUPERVISION =
+ "android.app.supervision.action.ENABLE_SUPERVISION";
/**
* Activity action: ask the human user to disable supervision for this user. Only the app that
@@ -62,7 +74,7 @@ public class SupervisionManager {
* @hide
*/
public static final String ACTION_DISABLE_SUPERVISION =
- "android.app.action.DISABLE_SUPERVISION";
+ "android.app.supervision.action.DISABLE_SUPERVISION";
/** @hide */
@UnsupportedAppUsage
@@ -72,11 +84,46 @@ public class SupervisionManager {
}
/**
+ * Creates an {@link Intent} that can be used with {@link Context#startActivity(Intent)} to
+ * launch the activity to verify supervision credentials.
+ *
+ * <p>A valid {@link Intent} is always returned if supervision is enabled at the time this API
+ * is called, the launched activity still need to perform validity checks as the supervision
+ * state can change when the activity is launched. A null intent is returned if supervision is
+ * disabled at the time of this API call.
+ *
+ * <p>A result code of {@link android.app.Activity#RESULT_OK} indicates successful verification
+ * of the supervision credentials.
+ *
+ * @hide
+ */
+ @RequiresPermission(value = android.Manifest.permission.QUERY_USERS)
+ @Nullable
+ public Intent createConfirmSupervisionCredentialsIntent() {
+ if (mService != null) {
+ try {
+ Intent result = mService.createConfirmSupervisionCredentialsIntent();
+ if (result != null) {
+ result.prepareToEnterProcess(
+ Intent.LOCAL_FLAG_FROM_SYSTEM, mContext.getAttributionSource());
+ }
+ return result;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns whether the device is supervised.
*
* @hide
*/
- @UserHandleAware
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SUPERVISION_MANAGER_APIS)
+ @RequiresPermission(anyOf = {MANAGE_USERS, QUERY_USERS})
+ @UserHandleAware(requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
public boolean isSupervisionEnabled() {
return isSupervisionEnabledForUser(mContext.getUserId());
}
@@ -84,14 +131,10 @@ public class SupervisionManager {
/**
* Returns whether the device is supervised.
*
- * <p>The caller must be from the same user as the target or hold the {@link
- * android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
- *
* @hide
*/
- @RequiresPermission(
- value = android.Manifest.permission.INTERACT_ACROSS_USERS,
- conditional = true)
+ @RequiresPermission(anyOf = {MANAGE_USERS, QUERY_USERS})
+ @UserHandleAware(requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
public boolean isSupervisionEnabledForUser(@UserIdInt int userId) {
if (mService != null) {
try {
@@ -108,7 +151,8 @@ public class SupervisionManager {
*
* @hide
*/
- @UserHandleAware
+ @TestApi
+ @UserHandleAware(requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
public void setSupervisionEnabled(boolean enabled) {
setSupervisionEnabledForUser(mContext.getUserId(), enabled);
}
@@ -116,14 +160,9 @@ public class SupervisionManager {
/**
* Sets whether the device is supervised for a given user.
*
- * <p>The caller must be from the same user as the target or hold the {@link
- * android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
- *
* @hide
*/
- @RequiresPermission(
- value = android.Manifest.permission.INTERACT_ACROSS_USERS,
- conditional = true)
+ @UserHandleAware(requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
public void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled) {
if (mService != null) {
try {
diff --git a/core/java/android/app/supervision/flags.aconfig b/core/java/android/app/supervision/flags.aconfig
index 232883cbfe00..94de03877fd7 100644
--- a/core/java/android/app/supervision/flags.aconfig
+++ b/core/java/android/app/supervision/flags.aconfig
@@ -64,3 +64,11 @@ flag {
description: "Flag that enables the Supervision pin recovery screen with Supervision settings entry point"
bug: "390500290"
}
+
+flag {
+ name: "supervision_manager_apis"
+ is_exported: true
+ namespace: "supervision"
+ description: "Flag that enables system APIs in Supervision Manager"
+ bug: "382034839"
+}
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index 9914ba2b020a..58bf4ef8100b 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -97,16 +97,6 @@ flag {
}
flag {
- name: "check_remote_views_uri_permission"
- namespace: "app_widgets"
- description: "Check that the widget provider has permissions to access any URIs within its RemoteViews"
- bug: "369137473"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "engagement_metrics"
namespace: "app_widgets"
description: "Enable collection of widget engagement metrics"
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index fcdb02ab5da2..ba1473cf5ed7 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -120,6 +120,16 @@ flag {
}
flag {
+ name: "correct_virtual_display_power_state"
+ namespace: "virtual_devices"
+ description: "Fix the virtual display power state"
+ bug: "371125136"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "vdm_settings"
namespace: "virtual_devices"
description: "Show virtual devices in Settings"
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index ffed5366d31b..ebf522b66c4e 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -34,6 +34,7 @@ import android.os.UserHandle;
import android.permission.PermissionManager;
import android.permission.flags.Flags;
import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.annotations.Immutable;
@@ -90,6 +91,7 @@ import java.util.Set;
*/
@Immutable
public final class AttributionSource implements Parcelable {
+ private static final String TAG = "AttributionSource";
private static final String DESCRIPTOR = "android.content.AttributionSource";
private static final Binder sDefaultToken = new Binder(DESCRIPTOR);
@@ -273,6 +275,13 @@ public final class AttributionSource implements Parcelable {
final AttributionSource globalSource = ActivityThread.currentAttributionSource();
if (globalSource != null) {
+ if (Flags.enforceDefaultDeviceIdInMyAttributionSource()
+ && globalSource.getDeviceId() != Context.DEVICE_ID_DEFAULT) {
+ Log.w(TAG,
+ "Avoid using myAttributionSource() to fetch an attributionSource with a "
+ + "non-default device Id");
+ return globalSource.withDeviceId(Context.DEVICE_ID_DEFAULT);
+ }
return globalSource;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8378695fd7a7..55d78f9b8c48 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -17,8 +17,8 @@
package android.content;
import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
-import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS;
import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE;
+import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS;
import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
import android.annotation.AttrRes;
@@ -3334,7 +3334,7 @@ public abstract class Context {
* this case, only one of these can be returned directly by the function;
* which of these that is returned is arbitrarily decided by the system.
*
- * <p>If you know the Intent your are registering for is sticky, you can
+ * <p>If you know the Intent you are registering for is sticky, you can
* supply null for your <var>receiver</var>. In this case, no receiver is
* registered -- the function simply returns the sticky Intent that
* matches <var>filter</var>. In the case of multiple matches, the same
@@ -6858,6 +6858,8 @@ public abstract class Context {
* @see android.app.supervision.SupervisionManager
* @hide
*/
+ @SystemApi
+ @FlaggedApi(android.app.supervision.flags.Flags.FLAG_SUPERVISION_MANAGER_APIS)
public static final String SUPERVISION_SERVICE = "supervision";
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0312ad7a739a..038756148a32 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -8181,7 +8181,7 @@ public class Intent implements Parcelable, Cloneable {
/**
* Create an intent from a URI. This URI may encode the action,
* category, and other intent fields, if it was returned by
- * {@link #toUri}. If the Intent was not generate by toUri(), its data
+ * {@link #toUri}. If the Intent was not generated by toUri(), its data
* will be the entire URI and its action will be ACTION_VIEW.
*
* <p>The URI given here must not be relative -- that is, it must include
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index e6082d0df1f8..5c904c15e706 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -622,3 +622,10 @@ flag {
description: "Add API to logout user"
bug: "350045389"
}
+
+flag {
+ name: "enable_moving_content_into_private_space"
+ namespace: "profile_experiences"
+ description: "Enable moving content into the Private Space"
+ bug: "360066001"
+}
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index 075457885586..f538e9ffffdd 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -25,6 +25,7 @@ import android.content.res.loader.ResourcesProvider;
import android.ravenwood.annotation.RavenwoodClassLoadHook;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.text.TextUtils;
+import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -50,6 +51,7 @@ import java.util.Objects;
@RavenwoodKeepWholeClass
@RavenwoodClassLoadHook(RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
public final class ApkAssets {
+ private static final boolean DEBUG = false;
/**
* The apk assets contains framework resource values specified by the system.
@@ -134,6 +136,17 @@ public final class ApkAssets {
@Nullable
private final AssetsProvider mAssets;
+ @NonNull
+ private String mName;
+
+ private static final int UPTODATE_FALSE = 0;
+ private static final int UPTODATE_TRUE = 1;
+ private static final int UPTODATE_ALWAYS_TRUE = 2;
+
+ // Start with the only value that may change later and would force a native call to
+ // double check it.
+ private int mPreviousUpToDateResult = UPTODATE_TRUE;
+
/**
* Creates a new ApkAssets instance from the given path on disk.
*
@@ -304,7 +317,7 @@ public final class ApkAssets {
private ApkAssets(@FormatType int format, @NonNull String path, @PropertyFlags int flags,
@Nullable AssetsProvider assets) throws IOException {
- this(format, flags, assets);
+ this(format, flags, assets, path);
Objects.requireNonNull(path, "path");
mNativePtr = nativeLoad(format, path, flags, assets);
mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
@@ -313,7 +326,7 @@ public final class ApkAssets {
private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd,
@NonNull String friendlyName, @PropertyFlags int flags, @Nullable AssetsProvider assets)
throws IOException {
- this(format, flags, assets);
+ this(format, flags, assets, friendlyName);
Objects.requireNonNull(fd, "fd");
Objects.requireNonNull(friendlyName, "friendlyName");
mNativePtr = nativeLoadFd(format, fd, friendlyName, flags, assets);
@@ -323,7 +336,7 @@ public final class ApkAssets {
private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd,
@NonNull String friendlyName, long offset, long length, @PropertyFlags int flags,
@Nullable AssetsProvider assets) throws IOException {
- this(format, flags, assets);
+ this(format, flags, assets, friendlyName);
Objects.requireNonNull(fd, "fd");
Objects.requireNonNull(friendlyName, "friendlyName");
mNativePtr = nativeLoadFdOffsets(format, fd, friendlyName, offset, length, flags, assets);
@@ -331,16 +344,17 @@ public final class ApkAssets {
}
private ApkAssets(@PropertyFlags int flags, @Nullable AssetsProvider assets) {
- this(FORMAT_APK, flags, assets);
+ this(FORMAT_APK, flags, assets, "empty");
mNativePtr = nativeLoadEmpty(flags, assets);
mStringBlock = null;
}
private ApkAssets(@FormatType int format, @PropertyFlags int flags,
- @Nullable AssetsProvider assets) {
+ @Nullable AssetsProvider assets, @NonNull String name) {
mFlags = flags;
mAssets = assets;
mIsOverlay = format == FORMAT_IDMAP;
+ if (DEBUG) mName = name;
}
@UnsupportedAppUsage
@@ -421,13 +435,41 @@ public final class ApkAssets {
}
}
+ private static double intervalMs(long beginNs, long endNs) {
+ return (endNs - beginNs) / 1000000.0;
+ }
+
/**
* Returns false if the underlying APK was changed since this ApkAssets was loaded.
*/
public boolean isUpToDate() {
+ // This function is performance-critical - it's called multiple times on every Resources
+ // object creation, and on few other cache accesses - so it's important to avoid the native
+ // call when we know for sure what it will return (which is the case for both ALWAYS_TRUE
+ // and FALSE).
+ if (mPreviousUpToDateResult != UPTODATE_TRUE) {
+ return mPreviousUpToDateResult == UPTODATE_ALWAYS_TRUE;
+ }
+ final long beforeTs, afterLockTs, afterNativeTs, afterUnlockTs;
+ if (DEBUG) beforeTs = System.nanoTime();
+ final int res;
synchronized (this) {
- return nativeIsUpToDate(mNativePtr);
+ if (DEBUG) afterLockTs = System.nanoTime();
+ res = nativeIsUpToDate(mNativePtr);
+ if (DEBUG) afterNativeTs = System.nanoTime();
+ }
+ if (DEBUG) {
+ afterUnlockTs = System.nanoTime();
+ if (afterUnlockTs - beforeTs >= 10L * 1000000) {
+ Log.d("ApkAssets", "isUpToDate(" + mName + ") took "
+ + intervalMs(beforeTs, afterUnlockTs)
+ + " ms: " + intervalMs(beforeTs, afterLockTs)
+ + " / " + intervalMs(afterLockTs, afterNativeTs)
+ + " / " + intervalMs(afterNativeTs, afterUnlockTs));
+ }
}
+ mPreviousUpToDateResult = res;
+ return res != UPTODATE_FALSE;
}
public boolean isSystem() {
@@ -487,7 +529,7 @@ public final class ApkAssets {
private static native @NonNull String nativeGetAssetPath(long ptr);
private static native @NonNull String nativeGetDebugName(long ptr);
private static native long nativeGetStringBlock(long ptr);
- @CriticalNative private static native boolean nativeIsUpToDate(long ptr);
+ @CriticalNative private static native int nativeIsUpToDate(long ptr);
private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
private static native @Nullable OverlayableInfo nativeGetOverlayableInfo(long ptr,
String overlayableName) throws IOException;
diff --git a/core/java/android/content/res/ResourceTimer.java b/core/java/android/content/res/ResourceTimer.java
index d51f64ce8106..2d1bf4d9d296 100644
--- a/core/java/android/content/res/ResourceTimer.java
+++ b/core/java/android/content/res/ResourceTimer.java
@@ -17,13 +17,10 @@
package android.content.res;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-
import android.app.AppProtoEnums;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemClock;
import android.text.TextUtils;
@@ -33,6 +30,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
+import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -277,38 +275,40 @@ public final class ResourceTimer {
* Update the metrics information and dump it.
* @hide
*/
- public static void dumpTimers(@NonNull ParcelFileDescriptor pfd, @Nullable String[] args) {
- FileOutputStream fout = new FileOutputStream(pfd.getFileDescriptor());
- PrintWriter pw = new FastPrintWriter(fout);
- synchronized (sLock) {
- if (!sEnabled || (sConfig == null)) {
+ public static void dumpTimers(@NonNull FileDescriptor fd, String... args) {
+ try (PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd))) {
+ pw.println("\nDumping ResourceTimers");
+
+ final boolean enabled;
+ synchronized (sLock) {
+ enabled = sEnabled && sConfig != null;
+ }
+ if (!enabled) {
pw.println(" Timers are not enabled in this process");
- pw.flush();
return;
}
- }
- // Look for the --refresh switch. If the switch is present, then sTimers is updated.
- // Otherwise, the current value of sTimers is displayed.
- boolean refresh = Arrays.asList(args).contains("-refresh");
-
- synchronized (sLock) {
- update(refresh);
- long runtime = sLastUpdated - sProcessStart;
- pw.format(" config runtime=%d proc=%s\n", runtime, Process.myProcessName());
- for (int i = 0; i < sTimers.length; i++) {
- Timer t = sTimers[i];
- if (t.count != 0) {
- String name = sConfig.timers[i];
- pw.format(" stats timer=%s cnt=%d avg=%d min=%d max=%d pval=%s "
- + "largest=%s\n",
- name, t.count, t.total / t.count, t.mintime, t.maxtime,
- packedString(t.percentile),
- packedString(t.largest));
+ // Look for the --refresh switch. If the switch is present, then sTimers is updated.
+ // Otherwise, the current value of sTimers is displayed.
+ boolean refresh = Arrays.asList(args).contains("-refresh");
+
+ synchronized (sLock) {
+ update(refresh);
+ long runtime = sLastUpdated - sProcessStart;
+ pw.format(" config runtime=%d proc=%s\n", runtime, Process.myProcessName());
+ for (int i = 0; i < sTimers.length; i++) {
+ Timer t = sTimers[i];
+ if (t.count != 0) {
+ String name = sConfig.timers[i];
+ pw.format(" stats timer=%s cnt=%d avg=%d min=%d max=%d pval=%s "
+ + "largest=%s\n",
+ name, t.count, t.total / t.count, t.mintime, t.maxtime,
+ packedString(t.percentile),
+ packedString(t.largest));
+ }
}
}
}
- pw.flush();
}
// Enable (or disabled) the runtime timers. Note that timers are disabled by default. This
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index 40c532498fbc..36fa05905814 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -29,6 +29,8 @@ import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.util.TypedValue;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.pkg.component.AconfigFlags;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.XmlUtils;
import dalvik.annotation.optimization.CriticalNative;
@@ -50,6 +52,7 @@ import java.io.Reader;
@RavenwoodClassLoadHook(RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
public final class XmlBlock implements AutoCloseable {
private static final boolean DEBUG=false;
+ public static final String ANDROID_RESOURCES = "http://schemas.android.com/apk/res/android";
@UnsupportedAppUsage
public XmlBlock(byte[] data) {
@@ -343,6 +346,23 @@ public final class XmlBlock implements AutoCloseable {
if (ev == ERROR_BAD_DOCUMENT) {
throw new XmlPullParserException("Corrupt XML binary file");
}
+ if (useLayoutReadwrite() && ev == START_TAG) {
+ AconfigFlags flags = ParsingPackageUtils.getAconfigFlags();
+ if (flags.skipCurrentElement(/* pkg= */ null, this)) {
+ int depth = 1;
+ while (depth > 0) {
+ int ev2 = nativeNext(mParseState);
+ if (ev2 == ERROR_BAD_DOCUMENT) {
+ throw new XmlPullParserException("Corrupt XML binary file");
+ } else if (ev2 == START_TAG) {
+ depth++;
+ } else if (ev2 == END_TAG) {
+ depth--;
+ }
+ }
+ return next();
+ }
+ }
if (mDecNextDepth) {
mDepth--;
mDecNextDepth = false;
@@ -368,6 +388,18 @@ public final class XmlBlock implements AutoCloseable {
}
return ev;
}
+
+ // Until ravenwood supports AconfigFlags, we just don't do layoutReadwriteFlags().
+ @android.ravenwood.annotation.RavenwoodReplace(
+ bug = 396458006, blockedBy = AconfigFlags.class)
+ private static boolean useLayoutReadwrite() {
+ return Flags.layoutReadwriteFlags();
+ }
+
+ private static boolean useLayoutReadwrite$ravenwood() {
+ return false;
+ }
+
public void require(int type, String namespace, String name) throws XmlPullParserException,IOException {
if (type != getEventType()
|| (namespace != null && !namespace.equals( getNamespace () ) )
diff --git a/core/java/android/hardware/contexthub/HubEndpointSession.java b/core/java/android/hardware/contexthub/HubEndpointSession.java
index dd6e52f51df0..ca59be8fcc65 100644
--- a/core/java/android/hardware/contexthub/HubEndpointSession.java
+++ b/core/java/android/hardware/contexthub/HubEndpointSession.java
@@ -27,6 +27,7 @@ import android.hardware.location.ContextHubTransactionHelper;
import android.hardware.location.IContextHubTransactionCallback;
import android.util.CloseGuard;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -160,6 +161,32 @@ public class HubEndpointSession implements AutoCloseable {
return stringBuilder.toString();
}
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+
+ boolean isEqual = false;
+ if (object instanceof HubEndpointSession other) {
+ isEqual = (other.getId() == mId);
+ if (mServiceDescriptor != null) {
+ isEqual &= mServiceDescriptor.equals(other.getServiceDescriptor());
+ } else {
+ isEqual &= (other.getServiceDescriptor() == null);
+ }
+ isEqual &=
+ mInitiator.equals(other.mInitiator) && mDestination.equals(other.mDestination);
+ }
+
+ return isEqual;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mServiceDescriptor, mInitiator, mDestination);
+ }
+
/** @hide */
protected void finalize() throws Throwable {
try {
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index 0d9db1fa3c91..7debab946bc0 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -17,7 +17,6 @@
package android.hardware.display;
import android.Manifest;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -401,7 +400,6 @@ public final class ColorDisplayManager {
* @hide
*/
@TestApi
- @FlaggedApi(android.app.Flags.FLAG_MODES_API)
@RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
public boolean isSaturationActivated() {
return mManager.isSaturationActivated();
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index d8919160320a..7850e377ec4d 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -612,6 +612,7 @@ public final class DisplayManager {
PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS,
PRIVATE_EVENT_TYPE_HDR_SDR_RATIO_CHANGED,
PRIVATE_EVENT_TYPE_DISPLAY_CONNECTION_CHANGED,
+ PRIVATE_EVENT_TYPE_DISPLAY_COMMITTED_STATE_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface PrivateEventType {}
@@ -677,7 +678,7 @@ public final class DisplayManager {
* through the {@link DisplayListener#onDisplayChanged} callback method. New brightness
* values can be retrieved via {@link android.view.Display#getBrightnessInfo()}.
*
- * @see #registerDisplayListener(DisplayListener, Handler, long)
+ * @see #registerDisplayListener(DisplayListener, Handler, long, long)
*
* @hide
*/
@@ -690,7 +691,7 @@ public final class DisplayManager {
*
* Requires that {@link Display#isHdrSdrRatioAvailable()} is true.
*
- * @see #registerDisplayListener(DisplayListener, Handler, long)
+ * @see #registerDisplayListener(DisplayListener, Handler, long, long)
*
* @hide
*/
@@ -699,11 +700,19 @@ public final class DisplayManager {
/**
* Event type to register for a display's connection changed.
*
- * @see #registerDisplayListener(DisplayListener, Handler, long)
+ * @see #registerDisplayListener(DisplayListener, Handler, long, long)
* @hide
*/
public static final long PRIVATE_EVENT_TYPE_DISPLAY_CONNECTION_CHANGED = 1L << 2;
+ /**
+ * Event type to register for a display's committed state changes.
+ *
+ * @see #registerDisplayListener(DisplayListener, Handler, long, long)
+ * @hide
+ */
+ public static final long PRIVATE_EVENT_TYPE_DISPLAY_COMMITTED_STATE_CHANGED = 1L << 3;
+
/** @hide */
public DisplayManager(Context context) {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 339dbf2c2029..a7d610e54e2c 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -113,7 +113,8 @@ public final class DisplayManagerGlobal {
EVENT_DISPLAY_CONNECTED,
EVENT_DISPLAY_DISCONNECTED,
EVENT_DISPLAY_REFRESH_RATE_CHANGED,
- EVENT_DISPLAY_STATE_CHANGED
+ EVENT_DISPLAY_STATE_CHANGED,
+ EVENT_DISPLAY_COMMITTED_STATE_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisplayEvent {}
@@ -128,6 +129,8 @@ public final class DisplayManagerGlobal {
public static final int EVENT_DISPLAY_DISCONNECTED = 7;
public static final int EVENT_DISPLAY_REFRESH_RATE_CHANGED = 8;
public static final int EVENT_DISPLAY_STATE_CHANGED = 9;
+ public static final int EVENT_DISPLAY_COMMITTED_STATE_CHANGED = 10;
+
@LongDef(prefix = {"INTERNAL_EVENT_FLAG_"}, flag = true, value = {
INTERNAL_EVENT_FLAG_DISPLAY_ADDED,
@@ -139,6 +142,7 @@ public final class DisplayManagerGlobal {
INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE,
INTERNAL_EVENT_FLAG_DISPLAY_STATE,
INTERNAL_EVENT_FLAG_TOPOLOGY_UPDATED,
+ INTERNAL_EVENT_FLAG_DISPLAY_COMMITTED_STATE_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface InternalEventFlag {}
@@ -152,6 +156,8 @@ public final class DisplayManagerGlobal {
public static final long INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE = 1L << 6;
public static final long INTERNAL_EVENT_FLAG_DISPLAY_STATE = 1L << 7;
public static final long INTERNAL_EVENT_FLAG_TOPOLOGY_UPDATED = 1L << 8;
+ public static final long INTERNAL_EVENT_FLAG_DISPLAY_COMMITTED_STATE_CHANGED = 1L << 9;
+
@UnsupportedAppUsage
private static DisplayManagerGlobal sInstance;
@@ -1550,6 +1556,12 @@ public final class DisplayManagerGlobal {
mListener.onDisplayChanged(displayId);
}
break;
+ case EVENT_DISPLAY_COMMITTED_STATE_CHANGED:
+ if ((mInternalEventFlagsMask
+ & INTERNAL_EVENT_FLAG_DISPLAY_COMMITTED_STATE_CHANGED) != 0) {
+ mListener.onDisplayChanged(displayId);
+ }
+ break;
}
if (DEBUG) {
Trace.endSection();
@@ -1710,6 +1722,8 @@ public final class DisplayManagerGlobal {
return "EVENT_DISPLAY_REFRESH_RATE_CHANGED";
case EVENT_DISPLAY_STATE_CHANGED:
return "EVENT_DISPLAY_STATE_CHANGED";
+ case EVENT_DISPLAY_COMMITTED_STATE_CHANGED:
+ return "EVENT_DISPLAY_COMMITTED_STATE_CHANGED";
}
return "UNKNOWN";
}
@@ -1756,6 +1770,13 @@ public final class DisplayManagerGlobal {
& DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_CONNECTION_CHANGED) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED;
}
+
+ if (Flags.committedStateSeparateEvent()) {
+ if ((privateEventFlags
+ & DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_COMMITTED_STATE_CHANGED) != 0) {
+ baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_COMMITTED_STATE_CHANGED;
+ }
+ }
return baseEventMask;
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java b/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
index 48c5887d80d0..586830c8d189 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
@@ -224,6 +224,10 @@ public class FingerprintSensorConfigurations implements Parcelable {
} catch (RemoteException e) {
Log.d(TAG, "Unable to get sensor properties!");
}
+
+ if (props == null) {
+ props = new SensorProps[]{};
+ }
return props;
}
}
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 3d4b8854b01f..7c82abe083c2 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -386,7 +386,7 @@ public class InputSettings {
*/
public static boolean isTouchpadAccelerationEnabled(@NonNull Context context) {
if (!isPointerAccelerationFeatureFlagEnabled()) {
- return false;
+ return true;
}
return Settings.System.getIntForUser(context.getContentResolver(),
@@ -833,7 +833,7 @@ public class InputSettings {
*/
public static boolean isMousePointerAccelerationEnabled(@NonNull Context context) {
if (!isPointerAccelerationFeatureFlagEnabled()) {
- return false;
+ return true;
}
return Settings.System.getIntForUser(context.getContentResolver(),
diff --git a/media/java/android/media/Image.java b/core/java/android/media/Image.java
index 486063ed5f6b..486063ed5f6b 100644
--- a/media/java/android/media/Image.java
+++ b/core/java/android/media/Image.java
diff --git a/media/java/android/media/ImageReader.java b/core/java/android/media/ImageReader.java
index 530d48d3e60b..530d48d3e60b 100644
--- a/media/java/android/media/ImageReader.java
+++ b/core/java/android/media/ImageReader.java
diff --git a/media/java/android/media/ImageUtils.java b/core/java/android/media/ImageUtils.java
index 7c6ba838b24f..7c6ba838b24f 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/core/java/android/media/ImageUtils.java
diff --git a/media/java/android/media/ImageWriter.java b/core/java/android/media/ImageWriter.java
index 0a79f41e1ff0..0a79f41e1ff0 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/core/java/android/media/ImageWriter.java
diff --git a/media/java/android/media/PublicFormatUtils.java b/core/java/android/media/PublicFormatUtils.java
index 209e1c892045..209e1c892045 100644
--- a/media/java/android/media/PublicFormatUtils.java
+++ b/core/java/android/media/PublicFormatUtils.java
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c00f31db1a38..33bf4a29ecc6 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -982,8 +982,8 @@ public class UserManager {
/**
* Specifies if a user is disallowed from adding new users. This can only be set by device
* owners or profile owners on the main user. The default value is <code>false</code>.
- * <p> When the device is an organization-owned device provisioned with a managed profile,
- * this restriction will be set as a base restriction which cannot be removed by any admin.
+ * <p> When the device is an organization-owned device, this restriction will be set as
+ * a base restriction which cannot be removed by any admin.
*
* <p>Holders of the permission
* {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_MODIFY_USERS}
@@ -2776,7 +2776,7 @@ public class UserManager {
}
/**
- * Returns whether logging out is currently allowed for the context user.
+ * Returns whether logging out is currently allowed for the specified user.
*
* <p>Logging out is not allowed in the following cases:
* <ol>
@@ -2794,11 +2794,10 @@ public class UserManager {
* {@link #LOGOUTABILITY_STATUS_CANNOT_SWITCH}.
* @hide
*/
- @UserHandleAware
@RequiresPermission(Manifest.permission.MANAGE_USERS)
- public @UserLogoutability int getUserLogoutability() {
+ public @UserLogoutability int getUserLogoutability(@UserIdInt int userId) {
try {
- return mService.getUserLogoutability(mUserId);
+ return mService.getUserLogoutability(userId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/vibrator/VibratorFrequencyProfile.java b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
index 2b5f9bf2a22e..a8ed81846663 100644
--- a/core/java/android/os/vibrator/VibratorFrequencyProfile.java
+++ b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
@@ -51,8 +51,7 @@ public final class VibratorFrequencyProfile {
Preconditions.checkArgument(!frequencyProfile.isEmpty(),
"Frequency profile must not be empty");
mFrequencyProfile = frequencyProfile;
- mFrequenciesOutputAcceleration = generateFrequencyToAccelerationMap(
- frequencyProfile.getFrequenciesHz(), frequencyProfile.getOutputAccelerationsGs());
+ mFrequenciesOutputAcceleration = generateFrequencyToAccelerationMap(mFrequencyProfile);
}
/**
@@ -133,18 +132,21 @@ public final class VibratorFrequencyProfile {
}
private static SparseArray<Float> generateFrequencyToAccelerationMap(
- float[] frequencies, float[] accelerations) {
- SparseArray<Float> sparseArray = new SparseArray<>(frequencies.length);
-
+ VibratorInfo.FrequencyProfile frequencyProfile) {
+ float[] frequencies = frequencyProfile.getFrequenciesHz();
+ SparseArray<Float> frequencyToAcceleration = new SparseArray<>(frequencies.length);
+ int lastFrequency = -1;
for (int i = 0; i < frequencies.length; i++) {
int frequency = (int) frequencies[i];
- float acceleration = accelerations[i];
-
- sparseArray.put(frequency,
- Math.min(acceleration, sparseArray.get(frequency, Float.MAX_VALUE)));
+ if (frequency == lastFrequency) {
+ continue; // Skip duplicate frequencies
+ }
+ float acceleration = frequencyProfile.getOutputAccelerationGs(frequency);
+ frequencyToAcceleration.put(frequency, acceleration);
+ lastFrequency = frequency;
}
- return sparseArray;
+ return frequencyToAcceleration;
}
}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index daa5584462ba..d469a2f985fa 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -507,3 +507,10 @@ flag {
description: "Use IoThread handler for AppOpsService background/IO work."
bug: "394380603"
}
+
+flag {
+ name: "enforce_default_device_id_in_my_attribution_source"
+ namespace: "permissions"
+ description: "Force AttributionSource.myAttributionSource() to return a default device id"
+ bug: "343121936"
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f1a9514107da..1a9b42e46a1c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2119,7 +2119,6 @@ public final class Settings {
* <p>
* Output: Nothing.
*/
- @FlaggedApi(android.app.Flags.FLAG_MODES_API)
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_AUTOMATIC_ZEN_RULE_SETTINGS
= "android.settings.AUTOMATIC_ZEN_RULE_SETTINGS";
@@ -2129,7 +2128,6 @@ public final class Settings {
* <p>
* This must be passed as an extra field to the {@link #ACTION_AUTOMATIC_ZEN_RULE_SETTINGS}.
*/
- @FlaggedApi(android.app.Flags.FLAG_MODES_API)
public static final String EXTRA_AUTOMATIC_ZEN_RULE_ID
= "android.provider.extra.AUTOMATIC_ZEN_RULE_ID";
@@ -10269,6 +10267,16 @@ public final class Settings {
public static final String DOZE_ALWAYS_ON = "doze_always_on";
/**
+ * Indicates whether ambient wallpaper is visible with AOD.
+ * <p>
+ * Type: int (0 for false, 1 for true)
+ *
+ * @hide
+ */
+ public static final String DOZE_ALWAYS_ON_WALLPAPER_ENABLED =
+ "doze_always_on_wallpaper_enabled";
+
+ /**
* Whether the device should pulse on pick up gesture.
* @hide
*/
diff --git a/core/java/android/security/FileIntegrityManager.java b/core/java/android/security/FileIntegrityManager.java
index 9e02ecd19aee..903f8170104e 100644
--- a/core/java/android/security/FileIntegrityManager.java
+++ b/core/java/android/security/FileIntegrityManager.java
@@ -65,13 +65,7 @@ public final class FileIntegrityManager {
* other fs-verity APIs.
*/
public boolean isApkVeritySupported() {
- try {
- // Go through the service just to avoid exposing the vendor controlled system property
- // to all apps.
- return mService.isApkVeritySupported();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return VerityUtils.isFsVeritySupported();
}
/**
diff --git a/core/java/android/security/IFileIntegrityService.aidl b/core/java/android/security/IFileIntegrityService.aidl
index c6def239d59a..5a1a6a0ea6d9 100644
--- a/core/java/android/security/IFileIntegrityService.aidl
+++ b/core/java/android/security/IFileIntegrityService.aidl
@@ -24,8 +24,6 @@ import android.os.IInstalld;
* @hide
*/
interface IFileIntegrityService {
- boolean isApkVeritySupported();
-
IInstalld.IFsveritySetupAuthToken createAuthToken(in ParcelFileDescriptor authFd);
@EnforcePermission("SETUP_FSVERITY")
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 792e6ff52d01..3a3ea189b227 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -126,6 +126,16 @@ flag {
}
flag {
+ name: "internal_log_event_listener"
+ namespace: "hardware_backed_security"
+ description: "Use internal callback to gather SecurityMonitor logs."
+ bug: "389732143"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "protect_device_config_flags"
namespace: "psap_ai"
description: "Feature flag to limit adb shell to allowlisted flags"
diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
index 76ee4480c222..f5f334891d2d 100644
--- a/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
+++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java
@@ -19,10 +19,10 @@ package android.security.intrusiondetection;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.app.admin.ConnectEvent;
import android.app.admin.DnsEvent;
import android.app.admin.SecurityLog.SecurityEvent;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.security.Flags;
@@ -223,13 +223,13 @@ public final class IntrusionDetectionEvent implements Parcelable {
out.writeInt(mType);
switch (mType) {
case SECURITY_EVENT:
- out.writeParcelable(mSecurityEvent, flags);
+ mSecurityEvent.writeToParcel(out, flags);
break;
case NETWORK_EVENT_DNS:
- out.writeParcelable(mNetworkEventDns, flags);
+ mNetworkEventDns.writeToParcel(out, flags);
break;
case NETWORK_EVENT_CONNECT:
- out.writeParcelable(mNetworkEventConnect, flags);
+ mNetworkEventConnect.writeToParcel(out, flags);
break;
default:
throw new IllegalArgumentException("Invalid event type: " + mType);
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 6e771f8f0ffe..c375cfb900ac 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -18,11 +18,9 @@ package android.service.notification;
import static com.android.internal.util.Preconditions.checkArgument;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.Flags;
import android.content.Context;
import android.net.Uri;
import android.os.Parcel;
@@ -105,20 +103,15 @@ public final class Condition implements Parcelable {
public @interface Source {}
/** The state is changing due to an unknown reason. */
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int SOURCE_UNKNOWN = 0;
/** The state is changing due to an explicit user action. */
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int SOURCE_USER_ACTION = 1;
/** The state is changing due to an automatic schedule (alarm, set time, etc). */
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int SOURCE_SCHEDULE = 2;
/** The state is changing due to a change in context (such as detected driving or sleeping). */
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int SOURCE_CONTEXT = 3;
/** The source of, or reason for, the state change represented by this Condition. **/
- @FlaggedApi(Flags.FLAG_MODES_API)
public final @Source int source; // default = SOURCE_UNKNOWN
/**
@@ -145,7 +138,6 @@ public final class Condition implements Parcelable {
* @param state whether the mode should be activated or deactivated
* @param source the source of, or reason for, the state change represented by this Condition
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public Condition(@Nullable Uri id, @Nullable String summary, @State int state,
@Source int source) {
this(id, summary, "", "", -1, state, source, FLAG_RELEVANT_ALWAYS);
@@ -168,7 +160,6 @@ public final class Condition implements Parcelable {
* @param source the source of, or reason for, the state change represented by this Condition
* @param flags flags on this condition
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public Condition(@Nullable Uri id, @Nullable String summary, @Nullable String line1,
@Nullable String line2, int icon, @State int state, @Source int source,
int flags) {
@@ -195,15 +186,13 @@ public final class Condition implements Parcelable {
source.readString(),
source.readInt(),
source.readInt(),
- Flags.modesApi() ? source.readInt() : SOURCE_UNKNOWN,
+ source.readInt(),
source.readInt());
}
/** @hide */
public void validate() {
- if (Flags.modesApi()) {
- checkValidSource(source);
- }
+ checkValidSource(source);
}
private static boolean isValidState(int state) {
@@ -211,11 +200,9 @@ public final class Condition implements Parcelable {
}
private static int checkValidSource(@Source int source) {
- if (Flags.modesApi()) {
- checkArgument(source >= SOURCE_UNKNOWN && source <= SOURCE_CONTEXT,
- "Condition source must be one of SOURCE_UNKNOWN, SOURCE_USER_ACTION, "
- + "SOURCE_SCHEDULE, or SOURCE_CONTEXT");
- }
+ checkArgument(source >= SOURCE_UNKNOWN && source <= SOURCE_CONTEXT,
+ "Condition source must be one of SOURCE_UNKNOWN, SOURCE_USER_ACTION, "
+ + "SOURCE_SCHEDULE, or SOURCE_CONTEXT");
return source;
}
@@ -227,25 +214,21 @@ public final class Condition implements Parcelable {
dest.writeString(line2);
dest.writeInt(icon);
dest.writeInt(state);
- if (Flags.modesApi()) {
- dest.writeInt(this.source);
- }
+ dest.writeInt(this.source);
dest.writeInt(this.flags);
}
@Override
public String toString() {
- StringBuilder sb = new StringBuilder(Condition.class.getSimpleName()).append('[')
+ return new StringBuilder(Condition.class.getSimpleName()).append('[')
.append("state=").append(stateToString(state))
.append(",id=").append(id)
.append(",summary=").append(summary)
.append(",line1=").append(line1)
.append(",line2=").append(line2)
- .append(",icon=").append(icon);
- if (Flags.modesApi()) {
- sb.append(",source=").append(sourceToString(source));
- }
- return sb.append(",flags=").append(flags)
+ .append(",icon=").append(icon)
+ .append(",source=").append(sourceToString(source))
+ .append(",flags=").append(flags)
.append(']').toString();
}
@@ -279,7 +262,6 @@ public final class Condition implements Parcelable {
* Provides a human-readable string version of the Source enum.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static @NonNull String sourceToString(@Source int source) {
if (source == SOURCE_UNKNOWN) return "SOURCE_UNKNOWN";
if (source == SOURCE_USER_ACTION) return "SOURCE_USER_ACTION";
@@ -301,25 +283,19 @@ public final class Condition implements Parcelable {
if (!(o instanceof Condition)) return false;
if (o == this) return true;
final Condition other = (Condition) o;
- boolean finalEquals = Objects.equals(other.id, id)
+ return Objects.equals(other.id, id)
&& Objects.equals(other.summary, summary)
&& Objects.equals(other.line1, line1)
&& Objects.equals(other.line2, line2)
&& other.icon == icon
&& other.state == state
- && other.flags == flags;
- if (Flags.modesApi()) {
- return finalEquals && other.source == source;
- }
- return finalEquals;
+ && other.flags == flags
+ && other.source == source;
}
@Override
public int hashCode() {
- if (Flags.modesApi()) {
- return Objects.hash(id, summary, line1, line2, icon, state, source, flags);
- }
- return Objects.hash(id, summary, line1, line2, icon, state, flags);
+ return Objects.hash(id, summary, line1, line2, icon, state, source, flags);
}
@Override
diff --git a/core/java/android/service/notification/SystemZenRules.java b/core/java/android/service/notification/SystemZenRules.java
index f11ce1621f93..fbee06e113fc 100644
--- a/core/java/android/service/notification/SystemZenRules.java
+++ b/core/java/android/service/notification/SystemZenRules.java
@@ -16,7 +16,6 @@
package android.service.notification;
-import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
@@ -47,7 +46,6 @@ public final class SystemZenRules {
public static final String PACKAGE_ANDROID = "android";
/** Updates existing system-owned rules to use the new Modes fields (type, etc). */
- @FlaggedApi(Flags.FLAG_MODES_API)
public static void maybeUpgradeRules(Context context, ZenModeConfig config) {
for (ZenRule rule : config.automaticRules.values()) {
if (isSystemOwnedRule(rule)) {
@@ -69,7 +67,6 @@ public final class SystemZenRules {
return PACKAGE_ANDROID.equals(rule.pkg);
}
- @FlaggedApi(Flags.FLAG_MODES_API)
private static void upgradeSystemProviderRule(Context context, ZenRule rule) {
ScheduleInfo scheduleInfo = ZenModeConfig.tryParseScheduleConditionId(rule.conditionId);
if (scheduleInfo != null) {
diff --git a/core/java/android/service/notification/ZenAdapters.java b/core/java/android/service/notification/ZenAdapters.java
index a122b7155b18..4f53bfa841ef 100644
--- a/core/java/android/service/notification/ZenAdapters.java
+++ b/core/java/android/service/notification/ZenAdapters.java
@@ -17,7 +17,6 @@
package android.service.notification;
import android.annotation.NonNull;
-import android.app.Flags;
import android.app.NotificationManager.Policy;
/**
@@ -50,7 +49,8 @@ public class ZenAdapters {
: ZenPolicy.PEOPLE_TYPE_NONE)
.allowReminders(policy.allowReminders())
.allowRepeatCallers(policy.allowRepeatCallers())
- .allowSystem(policy.allowSystem());
+ .allowSystem(policy.allowSystem())
+ .allowPriorityChannels(policy.allowPriorityChannels());
if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
zenPolicyBuilder.showBadges(policy.showBadges())
@@ -62,10 +62,6 @@ public class ZenAdapters {
.showStatusBarIcons(policy.showStatusBarIcons());
}
- if (Flags.modesApi()) {
- zenPolicyBuilder.allowPriorityChannels(policy.allowPriorityChannels());
- }
-
return zenPolicyBuilder.build();
}
diff --git a/core/java/android/service/notification/ZenDeviceEffects.java b/core/java/android/service/notification/ZenDeviceEffects.java
index 06bd2555c2f8..d88fb3e35b1e 100644
--- a/core/java/android/service/notification/ZenDeviceEffects.java
+++ b/core/java/android/service/notification/ZenDeviceEffects.java
@@ -16,12 +16,10 @@
package android.service.notification;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
-import android.app.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -37,7 +35,6 @@ import java.util.Set;
* Represents the set of device effects (affecting display and device behavior in general) that
* are applied whenever an {@link android.app.AutomaticZenRule} is active.
*/
-@FlaggedApi(Flags.FLAG_MODES_API)
public final class ZenDeviceEffects implements Parcelable {
/**
@@ -157,7 +154,6 @@ public final class ZenDeviceEffects implements Parcelable {
}
/** @hide */
- @FlaggedApi(Flags.FLAG_MODES_API)
public void validate() {
int extraEffectsLength = 0;
for (String extraEffect : mExtraEffects) {
@@ -435,7 +431,6 @@ public final class ZenDeviceEffects implements Parcelable {
}
/** Builder class for {@link ZenDeviceEffects} objects. */
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final class Builder {
private boolean mGrayscale;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 4f459aa9131a..6f94c1b2d274 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -228,7 +228,7 @@ public class ZenModeConfig implements Parcelable {
private static final boolean DEFAULT_ALLOW_CONV = true;
private static final int DEFAULT_ALLOW_CONV_FROM = ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
private static final boolean DEFAULT_ALLOW_PRIORITY_CHANNELS = true;
- private static final boolean DEFAULT_CHANNELS_BYPASSING_DND = false;
+ private static final boolean DEFAULT_HAS_PRIORITY_CHANNELS = false;
// Default setting here is 010011101 = 157
private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS =
SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
@@ -242,9 +242,6 @@ public class ZenModeConfig implements Parcelable {
public static final int XML_VERSION_MODES_API = 11;
public static final int XML_VERSION_MODES_UI = 12;
- // TODO: b/310620812, b/344831624 - Update XML_VERSION and update default_zen_config.xml
- // accordingly when modes_api / modes_ui are inlined.
- private static final int XML_VERSION_PRE_MODES = 10;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -269,7 +266,7 @@ public class ZenModeConfig implements Parcelable {
private static final String DISALLOW_TAG = "disallow";
private static final String DISALLOW_ATT_VISUAL_EFFECTS = "visualEffects";
private static final String STATE_TAG = "state";
- private static final String STATE_ATT_CHANNELS_BYPASSING_DND = "areChannelsBypassingDnd";
+ private static final String STATE_HAS_PRIORITY_CHANNELS = "areChannelsBypassingDnd";
// zen policy visual effects attributes
private static final String SHOW_ATT_FULL_SCREEN_INTENT = "showFullScreenIntent";
@@ -303,7 +300,6 @@ public class ZenModeConfig implements Parcelable {
private static final String RULE_ATT_CONDITION_ID = "conditionId";
private static final String RULE_ATT_CREATION_TIME = "creationTime";
private static final String RULE_ATT_ENABLER = "enabler";
- private static final String RULE_ATT_MODIFIED = "modified";
private static final String RULE_ATT_ALLOW_MANUAL = "userInvokable";
private static final String RULE_ATT_TYPE = "type";
private static final String RULE_ATT_USER_MODIFIED_FIELDS = "userModifiedFields";
@@ -313,6 +309,7 @@ public class ZenModeConfig implements Parcelable {
private static final String RULE_ATT_DISABLED_ORIGIN = "disabledOrigin";
private static final String RULE_ATT_LEGACY_SUPPRESSED_EFFECTS = "legacySuppressedEffects";
private static final String RULE_ATT_CONDITION_OVERRIDE = "conditionOverride";
+ private static final String RULE_ATT_LAST_ACTIVATION = "lastActivation";
private static final String DEVICE_EFFECT_DISPLAY_GRAYSCALE = "zdeDisplayGrayscale";
private static final String DEVICE_EFFECT_SUPPRESS_AMBIENT_DISPLAY =
@@ -348,11 +345,11 @@ public class ZenModeConfig implements Parcelable {
public int allowConversationsFrom = DEFAULT_ALLOW_CONV_FROM;
public int user = UserHandle.USER_SYSTEM;
public int suppressedVisualEffects = DEFAULT_SUPPRESSED_VISUAL_EFFECTS;
- // Note that when the modes_api flag is true, the areChannelsBypassingDnd boolean only tracks
- // whether the current user has any priority channels. These channels may bypass DND when
- // allowPriorityChannels is true.
- // TODO: b/310620812 - Rename to be more accurate when modes_api flag is inlined.
- public boolean areChannelsBypassingDnd = DEFAULT_CHANNELS_BYPASSING_DND;
+ /**
+ * Whether the current user has any priority channels. These channels may bypass DND when
+ * {@link #allowPriorityChannels} is true.
+ */
+ public boolean hasPriorityChannels = DEFAULT_HAS_PRIORITY_CHANNELS;
public boolean allowPriorityChannels = DEFAULT_ALLOW_PRIORITY_CHANNELS;
public int version;
@@ -384,22 +381,18 @@ public class ZenModeConfig implements Parcelable {
user = source.readInt();
manualRule = source.readParcelable(null, ZenRule.class);
readRulesFromParcel(automaticRules, source);
- if (Flags.modesApi()) {
- readRulesFromParcel(deletedRules, source);
- }
+ readRulesFromParcel(deletedRules, source);
if (!Flags.modesUi()) {
allowAlarms = source.readInt() == 1;
allowMedia = source.readInt() == 1;
allowSystem = source.readInt() == 1;
suppressedVisualEffects = source.readInt();
}
- areChannelsBypassingDnd = source.readInt() == 1;
+ hasPriorityChannels = source.readInt() == 1;
if (!Flags.modesUi()) {
allowConversations = source.readBoolean();
allowConversationsFrom = source.readInt();
- if (Flags.modesApi()) {
- allowPriorityChannels = source.readBoolean();
- }
+ allowPriorityChannels = source.readBoolean();
}
}
@@ -493,22 +486,18 @@ public class ZenModeConfig implements Parcelable {
dest.writeInt(user);
dest.writeParcelable(manualRule, 0);
writeRulesToParcel(automaticRules, dest);
- if (Flags.modesApi()) {
- writeRulesToParcel(deletedRules, dest);
- }
+ writeRulesToParcel(deletedRules, dest);
if (!Flags.modesUi()) {
dest.writeInt(allowAlarms ? 1 : 0);
dest.writeInt(allowMedia ? 1 : 0);
dest.writeInt(allowSystem ? 1 : 0);
dest.writeInt(suppressedVisualEffects);
}
- dest.writeInt(areChannelsBypassingDnd ? 1 : 0);
+ dest.writeInt(hasPriorityChannels ? 1 : 0);
if (!Flags.modesUi()) {
dest.writeBoolean(allowConversations);
dest.writeInt(allowConversationsFrom);
- if (Flags.modesApi()) {
- dest.writeBoolean(allowPriorityChannels);
- }
+ dest.writeBoolean(allowPriorityChannels);
}
}
@@ -549,17 +538,13 @@ public class ZenModeConfig implements Parcelable {
(allowConversationsFrom))
.append("\nsuppressedVisualEffects=").append(suppressedVisualEffects);
}
- if (Flags.modesApi()) {
- sb.append("\nhasPriorityChannels=").append(areChannelsBypassingDnd);
- sb.append(",allowPriorityChannels=").append(allowPriorityChannels);
- } else {
- sb.append("\nareChannelsBypassingDnd=").append(areChannelsBypassingDnd);
- }
+
+ sb.append("\nhasPriorityChannels=").append(hasPriorityChannels);
+ sb.append(",allowPriorityChannels=").append(allowPriorityChannels);
sb.append(",\nautomaticRules=").append(rulesToString(automaticRules));
sb.append(",\nmanualRule=").append(manualRule);
- if (Flags.modesApi()) {
- sb.append(",\ndeletedRules=").append(rulesToString(deletedRules));
- }
+ sb.append(",\ndeletedRules=").append(rulesToString(deletedRules));
+
return sb.append(']').toString();
}
@@ -854,7 +839,7 @@ public class ZenModeConfig implements Parcelable {
final ZenModeConfig other = (ZenModeConfig) o;
// The policy fields that live on config are compared directly because the fields will
// contain data until MODES_UI is rolled out/cleaned up.
- boolean eq = other.allowAlarms == allowAlarms
+ return other.allowAlarms == allowAlarms
&& other.allowMedia == allowMedia
&& other.allowSystem == allowSystem
&& other.allowCalls == allowCalls
@@ -868,35 +853,23 @@ public class ZenModeConfig implements Parcelable {
&& Objects.equals(other.automaticRules, automaticRules)
&& Objects.equals(other.manualRule, manualRule)
&& other.suppressedVisualEffects == suppressedVisualEffects
- && other.areChannelsBypassingDnd == areChannelsBypassingDnd
+ && other.hasPriorityChannels == hasPriorityChannels
&& other.allowConversations == allowConversations
- && other.allowConversationsFrom == allowConversationsFrom;
- if (Flags.modesApi()) {
- return eq
- && Objects.equals(other.deletedRules, deletedRules)
- && other.allowPriorityChannels == allowPriorityChannels;
- }
- return eq;
+ && other.allowConversationsFrom == allowConversationsFrom
+ && Objects.equals(other.deletedRules, deletedRules)
+ && other.allowPriorityChannels == allowPriorityChannels;
}
@Override
public int hashCode() {
// The policy fields that live on config are compared directly because the fields will
// contain data until MODES_UI is rolled out/cleaned up.
- if (Flags.modesApi()) {
- return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
- allowRepeatCallers, allowMessages,
- allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
- user, automaticRules, manualRule,
- suppressedVisualEffects, areChannelsBypassingDnd, allowConversations,
- allowConversationsFrom, allowPriorityChannels);
- }
return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
allowRepeatCallers, allowMessages,
allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
user, automaticRules, manualRule,
- suppressedVisualEffects, areChannelsBypassingDnd, allowConversations,
- allowConversationsFrom);
+ suppressedVisualEffects, hasPriorityChannels, allowConversations,
+ allowConversationsFrom, allowPriorityChannels);
}
private static String toDayList(int[] days) {
@@ -952,10 +925,8 @@ public class ZenModeConfig implements Parcelable {
public static int getCurrentXmlVersion() {
if (Flags.modesUi()) {
return XML_VERSION_MODES_UI;
- } else if (Flags.modesApi()) {
- return XML_VERSION_MODES_API;
} else {
- return XML_VERSION_PRE_MODES;
+ return XML_VERSION_MODES_API;
}
}
@@ -1006,10 +977,8 @@ public class ZenModeConfig implements Parcelable {
rt.allowMedia = safeBoolean(parser, ALLOW_ATT_MEDIA,
DEFAULT_ALLOW_MEDIA);
rt.allowSystem = safeBoolean(parser, ALLOW_ATT_SYSTEM, DEFAULT_ALLOW_SYSTEM);
- if (Flags.modesApi()) {
- rt.allowPriorityChannels = safeBoolean(parser, ALLOW_ATT_CHANNELS,
- DEFAULT_ALLOW_PRIORITY_CHANNELS);
- }
+ rt.allowPriorityChannels = safeBoolean(parser, ALLOW_ATT_CHANNELS,
+ DEFAULT_ALLOW_PRIORITY_CHANNELS);
// migrate old suppressed visual effects fields, if they still exist in the xml
Boolean allowWhenScreenOff = unsafeBoolean(parser, ALLOW_ATT_SCREEN_OFF);
@@ -1054,13 +1023,12 @@ public class ZenModeConfig implements Parcelable {
} else {
readRuleCount++;
}
- } else if (AUTOMATIC_TAG.equals(tag)
- || (Flags.modesApi() && AUTOMATIC_DELETED_TAG.equals(tag))) {
+ } else if (AUTOMATIC_TAG.equals(tag) || AUTOMATIC_DELETED_TAG.equals(tag)) {
final String id = parser.getAttributeValue(null, RULE_ATT_ID);
if (id != null) {
final ZenRule automaticRule = readRuleXml(parser);
automaticRule.id = id;
- if (Flags.modesApi() && AUTOMATIC_DELETED_TAG.equals(tag)) {
+ if (AUTOMATIC_DELETED_TAG.equals(tag)) {
String deletedRuleKey = deletedRuleKey(automaticRule);
if (deletedRuleKey != null) {
rt.deletedRules.put(deletedRuleKey, automaticRule);
@@ -1071,8 +1039,8 @@ public class ZenModeConfig implements Parcelable {
}
}
} else if (STATE_TAG.equals(tag)) {
- rt.areChannelsBypassingDnd = safeBoolean(parser,
- STATE_ATT_CHANNELS_BYPASSING_DND, DEFAULT_CHANNELS_BYPASSING_DND);
+ rt.hasPriorityChannels = safeBoolean(parser,
+ STATE_HAS_PRIORITY_CHANNELS, DEFAULT_HAS_PRIORITY_CHANNELS);
}
}
if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
@@ -1149,9 +1117,7 @@ public class ZenModeConfig implements Parcelable {
out.attributeBoolean(null, ALLOW_ATT_SYSTEM, allowSystem);
out.attributeBoolean(null, ALLOW_ATT_CONV, allowConversations);
out.attributeInt(null, ALLOW_ATT_CONV_FROM, allowConversationsFrom);
- if (Flags.modesApi()) {
- out.attributeBoolean(null, ALLOW_ATT_CHANNELS, allowPriorityChannels);
- }
+ out.attributeBoolean(null, ALLOW_ATT_CHANNELS, allowPriorityChannels);
out.endTag(null, ALLOW_TAG);
out.startTag(null, DISALLOW_TAG);
@@ -1174,7 +1140,7 @@ public class ZenModeConfig implements Parcelable {
out.endTag(null, AUTOMATIC_TAG);
writtenRuleCount++;
}
- if (Flags.modesApi() && !forBackup) {
+ if (!forBackup) {
for (int i = 0; i < deletedRules.size(); i++) {
final ZenRule deletedRule = deletedRules.valueAt(i);
out.startTag(null, AUTOMATIC_DELETED_TAG);
@@ -1185,7 +1151,7 @@ public class ZenModeConfig implements Parcelable {
}
out.startTag(null, STATE_TAG);
- out.attributeBoolean(null, STATE_ATT_CHANNELS_BYPASSING_DND, areChannelsBypassingDnd);
+ out.attributeBoolean(null, STATE_HAS_PRIORITY_CHANNELS, hasPriorityChannels);
out.endTag(null, STATE_TAG);
out.endTag(null, ZEN_TAG);
@@ -1212,39 +1178,29 @@ public class ZenModeConfig implements Parcelable {
rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0);
rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER);
rt.condition = readConditionXml(parser);
-
- if (!Flags.modesApi() && rt.zenMode != ZEN_MODE_IMPORTANT_INTERRUPTIONS
- && Condition.isValidId(rt.conditionId, SYSTEM_AUTHORITY)) {
- // all default rules and user created rules updated to zenMode important interruptions
- Slog.i(TAG, "Updating zenMode of automatic rule " + rt.name);
- rt.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- }
- rt.modified = safeBoolean(parser, RULE_ATT_MODIFIED, false);
rt.zenPolicy = readZenPolicyXml(parser);
- if (Flags.modesApi()) {
- rt.zenDeviceEffects = readZenDeviceEffectsXml(parser);
- rt.allowManualInvocation = safeBoolean(parser, RULE_ATT_ALLOW_MANUAL, false);
- rt.iconResName = parser.getAttributeValue(null, RULE_ATT_ICON);
- rt.triggerDescription = parser.getAttributeValue(null, RULE_ATT_TRIGGER_DESC);
- rt.type = safeInt(parser, RULE_ATT_TYPE, AutomaticZenRule.TYPE_UNKNOWN);
- rt.userModifiedFields = safeInt(parser, RULE_ATT_USER_MODIFIED_FIELDS, 0);
- rt.zenPolicyUserModifiedFields = safeInt(parser, POLICY_USER_MODIFIED_FIELDS, 0);
- rt.zenDeviceEffectsUserModifiedFields = safeInt(parser,
- DEVICE_EFFECT_USER_MODIFIED_FIELDS, 0);
- Long deletionInstant = tryParseLong(
- parser.getAttributeValue(null, RULE_ATT_DELETION_INSTANT), null);
- if (deletionInstant != null) {
- rt.deletionInstant = Instant.ofEpochMilli(deletionInstant);
- }
- if (Flags.modesUi()) {
- rt.disabledOrigin = safeInt(parser, RULE_ATT_DISABLED_ORIGIN,
- ORIGIN_UNKNOWN);
- rt.legacySuppressedEffects = safeInt(parser,
- RULE_ATT_LEGACY_SUPPRESSED_EFFECTS, 0);
- rt.conditionOverride = safeInt(parser, RULE_ATT_CONDITION_OVERRIDE,
- ZenRule.OVERRIDE_NONE);
+ rt.zenDeviceEffects = readZenDeviceEffectsXml(parser);
+ rt.allowManualInvocation = safeBoolean(parser, RULE_ATT_ALLOW_MANUAL, false);
+ rt.iconResName = parser.getAttributeValue(null, RULE_ATT_ICON);
+ rt.triggerDescription = parser.getAttributeValue(null, RULE_ATT_TRIGGER_DESC);
+ rt.type = safeInt(parser, RULE_ATT_TYPE, AutomaticZenRule.TYPE_UNKNOWN);
+ rt.userModifiedFields = safeInt(parser, RULE_ATT_USER_MODIFIED_FIELDS, 0);
+ rt.zenPolicyUserModifiedFields = safeInt(parser, POLICY_USER_MODIFIED_FIELDS, 0);
+ rt.zenDeviceEffectsUserModifiedFields = safeInt(parser,
+ DEVICE_EFFECT_USER_MODIFIED_FIELDS, 0);
+ rt.deletionInstant = safeInstant(parser, RULE_ATT_DELETION_INSTANT, null);
+ if (Flags.modesUi()) {
+ rt.disabledOrigin = safeInt(parser, RULE_ATT_DISABLED_ORIGIN,
+ ORIGIN_UNKNOWN);
+ rt.legacySuppressedEffects = safeInt(parser,
+ RULE_ATT_LEGACY_SUPPRESSED_EFFECTS, 0);
+ rt.conditionOverride = safeInt(parser, RULE_ATT_CONDITION_OVERRIDE,
+ ZenRule.OVERRIDE_NONE);
+ if (Flags.modesCleanupImplicit()) {
+ rt.lastActivation = safeInstant(parser, RULE_ATT_LAST_ACTIVATION, null);
}
}
+
return rt;
}
@@ -1278,38 +1234,42 @@ public class ZenModeConfig implements Parcelable {
if (rule.zenPolicy != null) {
writeZenPolicyXml(rule.zenPolicy, out);
}
- if (Flags.modesApi() && rule.zenDeviceEffects != null) {
+ if (rule.zenDeviceEffects != null) {
writeZenDeviceEffectsXml(rule.zenDeviceEffects, out);
}
- out.attributeBoolean(null, RULE_ATT_MODIFIED, rule.modified);
- if (Flags.modesApi()) {
- out.attributeBoolean(null, RULE_ATT_ALLOW_MANUAL, rule.allowManualInvocation);
- if (rule.iconResName != null) {
- out.attribute(null, RULE_ATT_ICON, rule.iconResName);
- }
- if (rule.triggerDescription != null) {
- out.attribute(null, RULE_ATT_TRIGGER_DESC, rule.triggerDescription);
- }
- out.attributeInt(null, RULE_ATT_TYPE, rule.type);
- out.attributeInt(null, RULE_ATT_USER_MODIFIED_FIELDS, rule.userModifiedFields);
- out.attributeInt(null, POLICY_USER_MODIFIED_FIELDS, rule.zenPolicyUserModifiedFields);
- out.attributeInt(null, DEVICE_EFFECT_USER_MODIFIED_FIELDS,
- rule.zenDeviceEffectsUserModifiedFields);
- if (rule.deletionInstant != null) {
- out.attributeLong(null, RULE_ATT_DELETION_INSTANT,
- rule.deletionInstant.toEpochMilli());
+ out.attributeBoolean(null, RULE_ATT_ALLOW_MANUAL, rule.allowManualInvocation);
+ if (rule.iconResName != null) {
+ out.attribute(null, RULE_ATT_ICON, rule.iconResName);
+ }
+ if (rule.triggerDescription != null) {
+ out.attribute(null, RULE_ATT_TRIGGER_DESC, rule.triggerDescription);
+ }
+ out.attributeInt(null, RULE_ATT_TYPE, rule.type);
+ out.attributeInt(null, RULE_ATT_USER_MODIFIED_FIELDS, rule.userModifiedFields);
+ out.attributeInt(null, POLICY_USER_MODIFIED_FIELDS, rule.zenPolicyUserModifiedFields);
+ out.attributeInt(null, DEVICE_EFFECT_USER_MODIFIED_FIELDS,
+ rule.zenDeviceEffectsUserModifiedFields);
+ writeXmlAttributeInstant(out, RULE_ATT_DELETION_INSTANT, rule.deletionInstant);
+ if (Flags.modesUi()) {
+ out.attributeInt(null, RULE_ATT_DISABLED_ORIGIN, rule.disabledOrigin);
+ out.attributeInt(null, RULE_ATT_LEGACY_SUPPRESSED_EFFECTS,
+ rule.legacySuppressedEffects);
+ if (rule.conditionOverride == ZenRule.OVERRIDE_ACTIVATE && !forBackup) {
+ out.attributeInt(null, RULE_ATT_CONDITION_OVERRIDE, rule.conditionOverride);
}
- if (Flags.modesUi()) {
- out.attributeInt(null, RULE_ATT_DISABLED_ORIGIN, rule.disabledOrigin);
- out.attributeInt(null, RULE_ATT_LEGACY_SUPPRESSED_EFFECTS,
- rule.legacySuppressedEffects);
- if (rule.conditionOverride == ZenRule.OVERRIDE_ACTIVATE && !forBackup) {
- out.attributeInt(null, RULE_ATT_CONDITION_OVERRIDE, rule.conditionOverride);
- }
+ if (Flags.modesCleanupImplicit()) {
+ writeXmlAttributeInstant(out, RULE_ATT_LAST_ACTIVATION, rule.lastActivation);
}
}
}
+ private static void writeXmlAttributeInstant(TypedXmlSerializer out, String att,
+ @Nullable Instant instant) throws IOException {
+ if (instant != null) {
+ out.attributeLong(null, att, instant.toEpochMilli());
+ }
+ }
+
public static Condition readConditionXml(TypedXmlPullParser parser) {
final Uri id = safeUri(parser, CONDITION_ATT_ID);
if (id == null) return null;
@@ -1320,12 +1280,8 @@ public class ZenModeConfig implements Parcelable {
final int state = safeInt(parser, CONDITION_ATT_STATE, -1);
final int flags = safeInt(parser, CONDITION_ATT_FLAGS, -1);
try {
- if (Flags.modesApi()) {
- final int source = safeInt(parser, CONDITION_ATT_SOURCE, Condition.SOURCE_UNKNOWN);
- return new Condition(id, summary, line1, line2, icon, state, source, flags);
- } else {
- return new Condition(id, summary, line1, line2, icon, state, flags);
- }
+ final int source = safeInt(parser, CONDITION_ATT_SOURCE, Condition.SOURCE_UNKNOWN);
+ return new Condition(id, summary, line1, line2, icon, state, source, flags);
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Unable to read condition xml", e);
return null;
@@ -1339,9 +1295,7 @@ public class ZenModeConfig implements Parcelable {
out.attribute(null, CONDITION_ATT_LINE2, c.line2);
out.attributeInt(null, CONDITION_ATT_ICON, c.icon);
out.attributeInt(null, CONDITION_ATT_STATE, c.state);
- if (Flags.modesApi()) {
- out.attributeInt(null, CONDITION_ATT_SOURCE, c.source);
- }
+ out.attributeInt(null, CONDITION_ATT_SOURCE, c.source);
out.attributeInt(null, CONDITION_ATT_FLAGS, c.flags);
}
@@ -1363,12 +1317,11 @@ public class ZenModeConfig implements Parcelable {
final int system = safeInt(parser, ALLOW_ATT_SYSTEM, ZenPolicy.STATE_UNSET);
final int events = safeInt(parser, ALLOW_ATT_EVENTS, ZenPolicy.STATE_UNSET);
final int reminders = safeInt(parser, ALLOW_ATT_REMINDERS, ZenPolicy.STATE_UNSET);
- if (Flags.modesApi()) {
- final int channels = safeInt(parser, ALLOW_ATT_CHANNELS, ZenPolicy.STATE_UNSET);
- if (channels != ZenPolicy.STATE_UNSET) {
- builder.allowPriorityChannels(channels == STATE_ALLOW);
- policySet = true;
- }
+ final int channels = safeInt(parser, ALLOW_ATT_CHANNELS, ZenPolicy.STATE_UNSET);
+
+ if (channels != ZenPolicy.STATE_UNSET) {
+ builder.allowPriorityChannels(channels == STATE_ALLOW);
+ policySet = true;
}
if (calls != ZenPolicy.PEOPLE_TYPE_UNSET) {
@@ -1478,10 +1431,7 @@ public class ZenModeConfig implements Parcelable {
writeZenPolicyState(SHOW_ATT_AMBIENT, policy.getVisualEffectAmbient(), out);
writeZenPolicyState(SHOW_ATT_NOTIFICATION_LIST, policy.getVisualEffectNotificationList(),
out);
-
- if (Flags.modesApi()) {
- writeZenPolicyState(ALLOW_ATT_CHANNELS, policy.getPriorityChannelsAllowed(), out);
- }
+ writeZenPolicyState(ALLOW_ATT_CHANNELS, policy.getPriorityChannelsAllowed(), out);
}
private static void writeZenPolicyState(String attr, int val, TypedXmlSerializer out)
@@ -1495,7 +1445,7 @@ public class ZenModeConfig implements Parcelable {
if (val != ZenPolicy.CONVERSATION_SENDERS_UNSET) {
out.attributeInt(null, attr, val);
}
- } else if (Flags.modesApi() && Objects.equals(attr, ALLOW_ATT_CHANNELS)) {
+ } else if (Objects.equals(attr, ALLOW_ATT_CHANNELS)) {
if (val != ZenPolicy.STATE_UNSET) {
out.attributeInt(null, attr, val);
}
@@ -1506,7 +1456,6 @@ public class ZenModeConfig implements Parcelable {
}
}
- @FlaggedApi(Flags.FLAG_MODES_API)
@Nullable
private static ZenDeviceEffects readZenDeviceEffectsXml(TypedXmlPullParser parser) {
ZenDeviceEffects deviceEffects =
@@ -1539,7 +1488,6 @@ public class ZenModeConfig implements Parcelable {
return deviceEffects.hasEffects() ? deviceEffects : null;
}
- @FlaggedApi(Flags.FLAG_MODES_API)
private static void writeZenDeviceEffectsXml(ZenDeviceEffects deviceEffects,
TypedXmlSerializer out) throws IOException {
writeBooleanIfTrue(out, DEVICE_EFFECT_DISPLAY_GRAYSCALE,
@@ -1659,6 +1607,19 @@ public class ZenModeConfig implements Parcelable {
return values;
}
+ @Nullable
+ private static Instant safeInstant(TypedXmlPullParser parser, String att,
+ @Nullable Instant defValue) {
+ final String strValue = parser.getAttributeValue(null, att);
+ if (!TextUtils.isEmpty(strValue)) {
+ Long longValue = tryParseLong(strValue, null);
+ if (longValue != null) {
+ return Instant.ofEpochMilli(longValue);
+ }
+ }
+ return defValue;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -1732,9 +1693,7 @@ public class ZenModeConfig implements Parcelable {
(suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST) == 0);
}
- if (Flags.modesApi()) {
- builder.allowPriorityChannels(allowPriorityChannels);
- }
+ builder.allowPriorityChannels(allowPriorityChannels);
return builder.build();
}
@@ -1860,12 +1819,9 @@ public class ZenModeConfig implements Parcelable {
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
}
- int state = defaultPolicy.state;
- if (Flags.modesApi()) {
- state = Policy.policyState(defaultPolicy.hasPriorityChannels(),
- ZenPolicy.stateToBoolean(zenPolicy.getPriorityChannelsAllowed(),
- DEFAULT_ALLOW_PRIORITY_CHANNELS));
- }
+ int state = Policy.policyState(defaultPolicy.hasPriorityChannels(),
+ ZenPolicy.stateToBoolean(zenPolicy.getPriorityChannelsAllowed(),
+ DEFAULT_ALLOW_PRIORITY_CHANNELS));
return new NotificationManager.Policy(priorityCategories, callSenders,
messageSenders, suppressedVisualEffects, state, conversationSenders);
@@ -1930,7 +1886,7 @@ public class ZenModeConfig implements Parcelable {
priorityMessageSenders = peopleTypeToPrioritySenders(
manualRule.zenPolicy.getPriorityMessageSenders(), DEFAULT_SOURCE);
- state = Policy.policyState(areChannelsBypassingDnd,
+ state = Policy.policyState(hasPriorityChannels,
manualRule.zenPolicy.getPriorityChannelsAllowed() != STATE_DISALLOW);
boolean suppressFullScreenIntent = !manualRule.zenPolicy.isVisualEffectAllowed(
@@ -2030,10 +1986,7 @@ public class ZenModeConfig implements Parcelable {
priorityConversationSenders = zenPolicyConversationSendersToNotificationPolicy(
getAllowConversationsFrom(), priorityConversationSenders);
- state = areChannelsBypassingDnd ? Policy.STATE_CHANNELS_BYPASSING_DND : 0;
- if (Flags.modesApi()) {
- state = Policy.policyState(areChannelsBypassingDnd, allowPriorityChannels);
- }
+ state = Policy.policyState(hasPriorityChannels, allowPriorityChannels);
suppressedVisualEffects = getSuppressedVisualEffects();
}
@@ -2114,13 +2067,11 @@ public class ZenModeConfig implements Parcelable {
policy.priorityConversationSenders,
allowConversationsFrom);
if (policy.state != Policy.STATE_UNSET) {
- if (Flags.modesApi()) {
- setAllowPriorityChannels(policy.allowPriorityChannels());
- }
+ setAllowPriorityChannels(policy.allowPriorityChannels());
}
}
if (policy.state != Policy.STATE_UNSET) {
- areChannelsBypassingDnd = (policy.state & Policy.STATE_CHANNELS_BYPASSING_DND) != 0;
+ hasPriorityChannels = (policy.state & Policy.STATE_HAS_PRIORITY_CHANNELS) != 0;
}
}
@@ -2618,8 +2569,9 @@ public class ZenModeConfig implements Parcelable {
@UnsupportedAppUsage
public boolean enabled;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ // TODO: b/368247671 - Obsolete with MODES_UI; delete when the flag is inlined
@Deprecated
- public boolean snoozing; // user manually disabled this instance. Obsolete with MODES_UI
+ public boolean snoozing; // user manually disabled this instance.
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public String name; // required for automatic
@UnsupportedAppUsage
@@ -2635,9 +2587,7 @@ public class ZenModeConfig implements Parcelable {
// package name, only used for manual rules when they have turned DND on.
public String enabler;
public ZenPolicy zenPolicy;
- @FlaggedApi(Flags.FLAG_MODES_API)
@Nullable public ZenDeviceEffects zenDeviceEffects;
- public boolean modified; // rule has been modified from initial creation
public String pkg;
@AutomaticZenRule.Type
public int type = AutomaticZenRule.TYPE_UNKNOWN;
@@ -2668,6 +2618,18 @@ public class ZenModeConfig implements Parcelable {
@ConditionOverride
int conditionOverride = OVERRIDE_NONE;
+ /**
+ * Last time at which the rule was activated (for any reason, including overrides).
+ * If {@code null}, the rule has never been activated since its creation.
+ *
+ * <p>Note that this was previously untracked, so it will also be {@code null} for rules
+ * created before we started tracking and never activated since -- make sure to account for
+ * it, for example by falling back to {@link #creationTime} in logic involving this field.
+ */
+ @Nullable
+ @FlaggedApi(Flags.FLAG_MODES_CLEANUP_IMPLICIT)
+ public Instant lastActivation;
+
public ZenRule() { }
public ZenRule(Parcel source) {
@@ -2689,46 +2651,45 @@ public class ZenModeConfig implements Parcelable {
enabler = source.readString();
}
zenPolicy = source.readParcelable(null, android.service.notification.ZenPolicy.class);
- if (Flags.modesApi()) {
- zenDeviceEffects = source.readParcelable(null, ZenDeviceEffects.class);
- }
- modified = source.readInt() == 1;
+ zenDeviceEffects = source.readParcelable(null, ZenDeviceEffects.class);
pkg = source.readString();
- if (Flags.modesApi()) {
- allowManualInvocation = source.readBoolean();
- iconResName = source.readString();
- triggerDescription = source.readString();
- type = source.readInt();
- userModifiedFields = source.readInt();
- zenPolicyUserModifiedFields = source.readInt();
- zenDeviceEffectsUserModifiedFields = source.readInt();
- if (source.readInt() == 1) {
- deletionInstant = Instant.ofEpochMilli(source.readLong());
- }
- if (Flags.modesUi()) {
- disabledOrigin = source.readInt();
- legacySuppressedEffects = source.readInt();
- conditionOverride = source.readInt();
+ allowManualInvocation = source.readBoolean();
+ iconResName = source.readString();
+ triggerDescription = source.readString();
+ type = source.readInt();
+ userModifiedFields = source.readInt();
+ zenPolicyUserModifiedFields = source.readInt();
+ zenDeviceEffectsUserModifiedFields = source.readInt();
+ if (source.readInt() == 1) {
+ deletionInstant = Instant.ofEpochMilli(source.readLong());
+ }
+ if (Flags.modesUi()) {
+ disabledOrigin = source.readInt();
+ legacySuppressedEffects = source.readInt();
+ conditionOverride = source.readInt();
+ if (Flags.modesCleanupImplicit()) {
+ if (source.readInt() == 1) {
+ lastActivation = Instant.ofEpochMilli(source.readLong());
+ }
}
}
}
/**
- * Whether this ZenRule can be updated by an app. In general, rules that have been
- * customized by the user cannot be further updated by an app, with some exceptions:
+ * Whether this ZenRule has been customized by the user in any way.
+
+ * <p>In general, rules that have been customized by the user cannot be further updated by
+ * an app, with some exceptions:
* <ul>
* <li>Non user-configurable fields, like type, icon, configurationActivity, etc.
* <li>Name, if the name was not specifically modified by the user (to support language
* switches).
* </ul>
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
- public boolean canBeUpdatedByApp() {
- // The rule is considered updateable if its bitmask has no user modifications, and
- // the bitmasks of the policy and device effects have no modification.
- return userModifiedFields == 0
- && zenPolicyUserModifiedFields == 0
- && zenDeviceEffectsUserModifiedFields == 0;
+ public boolean isUserModified() {
+ return userModifiedFields != 0
+ || zenPolicyUserModifiedFields != 0
+ || zenDeviceEffectsUserModifiedFields != 0;
}
@Override
@@ -2765,29 +2726,32 @@ public class ZenModeConfig implements Parcelable {
dest.writeInt(0);
}
dest.writeParcelable(zenPolicy, 0);
- if (Flags.modesApi()) {
- dest.writeParcelable(zenDeviceEffects, 0);
- }
- dest.writeInt(modified ? 1 : 0);
+ dest.writeParcelable(zenDeviceEffects, 0);
dest.writeString(pkg);
- if (Flags.modesApi()) {
- dest.writeBoolean(allowManualInvocation);
- dest.writeString(iconResName);
- dest.writeString(triggerDescription);
- dest.writeInt(type);
- dest.writeInt(userModifiedFields);
- dest.writeInt(zenPolicyUserModifiedFields);
- dest.writeInt(zenDeviceEffectsUserModifiedFields);
- if (deletionInstant != null) {
- dest.writeInt(1);
- dest.writeLong(deletionInstant.toEpochMilli());
- } else {
- dest.writeInt(0);
- }
- if (Flags.modesUi()) {
- dest.writeInt(disabledOrigin);
- dest.writeInt(legacySuppressedEffects);
- dest.writeInt(conditionOverride);
+ dest.writeBoolean(allowManualInvocation);
+ dest.writeString(iconResName);
+ dest.writeString(triggerDescription);
+ dest.writeInt(type);
+ dest.writeInt(userModifiedFields);
+ dest.writeInt(zenPolicyUserModifiedFields);
+ dest.writeInt(zenDeviceEffectsUserModifiedFields);
+ if (deletionInstant != null) {
+ dest.writeInt(1);
+ dest.writeLong(deletionInstant.toEpochMilli());
+ } else {
+ dest.writeInt(0);
+ }
+ if (Flags.modesUi()) {
+ dest.writeInt(disabledOrigin);
+ dest.writeInt(legacySuppressedEffects);
+ dest.writeInt(conditionOverride);
+ if (Flags.modesCleanupImplicit()) {
+ if (lastActivation != null) {
+ dest.writeInt(1);
+ dest.writeLong(lastActivation.toEpochMilli());
+ } else {
+ dest.writeInt(0);
+ }
}
}
}
@@ -2816,34 +2780,33 @@ public class ZenModeConfig implements Parcelable {
.append(",creationTime=").append(creationTime)
.append(",enabler=").append(enabler)
.append(",zenPolicy=").append(zenPolicy)
- .append(",modified=").append(modified)
- .append(",condition=").append(condition);
-
- if (Flags.modesApi()) {
- sb.append(",deviceEffects=").append(zenDeviceEffects)
- .append(",allowManualInvocation=").append(allowManualInvocation)
- .append(",iconResName=").append(iconResName)
- .append(",triggerDescription=").append(triggerDescription)
- .append(",type=").append(type);
- if (userModifiedFields != 0) {
- sb.append(",userModifiedFields=")
- .append(AutomaticZenRule.fieldsToString(userModifiedFields));
- }
- if (zenPolicyUserModifiedFields != 0) {
- sb.append(",zenPolicyUserModifiedFields=")
- .append(ZenPolicy.fieldsToString(zenPolicyUserModifiedFields));
- }
- if (zenDeviceEffectsUserModifiedFields != 0) {
- sb.append(",zenDeviceEffectsUserModifiedFields=")
- .append(ZenDeviceEffects.fieldsToString(
- zenDeviceEffectsUserModifiedFields));
- }
- if (deletionInstant != null) {
- sb.append(",deletionInstant=").append(deletionInstant);
- }
- if (Flags.modesUi()) {
- sb.append(",disabledOrigin=").append(disabledOrigin);
- sb.append(",legacySuppressedEffects=").append(legacySuppressedEffects);
+ .append(",condition=").append(condition)
+ .append(",deviceEffects=").append(zenDeviceEffects)
+ .append(",allowManualInvocation=").append(allowManualInvocation)
+ .append(",iconResName=").append(iconResName)
+ .append(",triggerDescription=").append(triggerDescription)
+ .append(",type=").append(type);
+ if (userModifiedFields != 0) {
+ sb.append(",userModifiedFields=")
+ .append(AutomaticZenRule.fieldsToString(userModifiedFields));
+ }
+ if (zenPolicyUserModifiedFields != 0) {
+ sb.append(",zenPolicyUserModifiedFields=")
+ .append(ZenPolicy.fieldsToString(zenPolicyUserModifiedFields));
+ }
+ if (zenDeviceEffectsUserModifiedFields != 0) {
+ sb.append(",zenDeviceEffectsUserModifiedFields=")
+ .append(ZenDeviceEffects.fieldsToString(
+ zenDeviceEffectsUserModifiedFields));
+ }
+ if (deletionInstant != null) {
+ sb.append(",deletionInstant=").append(deletionInstant);
+ }
+ if (Flags.modesUi()) {
+ sb.append(",disabledOrigin=").append(disabledOrigin);
+ sb.append(",legacySuppressedEffects=").append(legacySuppressedEffects);
+ if (Flags.modesCleanupImplicit()) {
+ sb.append(",lastActivation=").append(lastActivation);
}
}
@@ -2869,7 +2832,7 @@ public class ZenModeConfig implements Parcelable {
proto.write(ZenRuleProto.CREATION_TIME_MS, creationTime);
proto.write(ZenRuleProto.ENABLED, enabled);
proto.write(ZenRuleProto.ENABLER, enabler);
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
proto.write(ZenRuleProto.IS_SNOOZING, conditionOverride == OVERRIDE_DEACTIVATE);
} else {
proto.write(ZenRuleProto.IS_SNOOZING, snoozing);
@@ -2887,7 +2850,6 @@ public class ZenModeConfig implements Parcelable {
if (zenPolicy != null) {
zenPolicy.dumpDebug(proto, ZenRuleProto.ZEN_POLICY);
}
- proto.write(ZenRuleProto.MODIFIED, modified);
proto.end(token);
}
@@ -2908,26 +2870,25 @@ public class ZenModeConfig implements Parcelable {
&& Objects.equals(other.enabler, enabler)
&& Objects.equals(other.zenPolicy, zenPolicy)
&& Objects.equals(other.pkg, pkg)
- && other.modified == modified;
+ && Objects.equals(other.zenDeviceEffects, zenDeviceEffects)
+ && other.allowManualInvocation == allowManualInvocation
+ && Objects.equals(other.iconResName, iconResName)
+ && Objects.equals(other.triggerDescription, triggerDescription)
+ && other.type == type
+ && other.userModifiedFields == userModifiedFields
+ && other.zenPolicyUserModifiedFields == zenPolicyUserModifiedFields
+ && other.zenDeviceEffectsUserModifiedFields
+ == zenDeviceEffectsUserModifiedFields
+ && Objects.equals(other.deletionInstant, deletionInstant);
- if (Flags.modesApi()) {
+ if (Flags.modesUi()) {
finalEquals = finalEquals
- && Objects.equals(other.zenDeviceEffects, zenDeviceEffects)
- && other.allowManualInvocation == allowManualInvocation
- && Objects.equals(other.iconResName, iconResName)
- && Objects.equals(other.triggerDescription, triggerDescription)
- && other.type == type
- && other.userModifiedFields == userModifiedFields
- && other.zenPolicyUserModifiedFields == zenPolicyUserModifiedFields
- && other.zenDeviceEffectsUserModifiedFields
- == zenDeviceEffectsUserModifiedFields
- && Objects.equals(other.deletionInstant, deletionInstant);
-
- if (Flags.modesUi()) {
+ && other.disabledOrigin == disabledOrigin
+ && other.legacySuppressedEffects == legacySuppressedEffects
+ && other.conditionOverride == conditionOverride;
+ if (Flags.modesCleanupImplicit()) {
finalEquals = finalEquals
- && other.disabledOrigin == disabledOrigin
- && other.legacySuppressedEffects == legacySuppressedEffects
- && other.conditionOverride == conditionOverride;
+ && Objects.equals(other.lastActivation, lastActivation);
}
}
@@ -2936,26 +2897,32 @@ public class ZenModeConfig implements Parcelable {
@Override
public int hashCode() {
- if (Flags.modesApi()) {
- if (Flags.modesUi()) {
+ if (Flags.modesUi()) {
+ if (Flags.modesCleanupImplicit()) {
return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
component, configurationActivity, pkg, id, enabler, zenPolicy,
- zenDeviceEffects, modified, allowManualInvocation, iconResName,
+ zenDeviceEffects, allowManualInvocation, iconResName,
triggerDescription, type, userModifiedFields,
zenPolicyUserModifiedFields, zenDeviceEffectsUserModifiedFields,
deletionInstant, disabledOrigin, legacySuppressedEffects,
- conditionOverride);
+ conditionOverride, lastActivation);
} else {
return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
component, configurationActivity, pkg, id, enabler, zenPolicy,
- zenDeviceEffects, modified, allowManualInvocation, iconResName,
+ zenDeviceEffects, allowManualInvocation, iconResName,
triggerDescription, type, userModifiedFields,
zenPolicyUserModifiedFields, zenDeviceEffectsUserModifiedFields,
- deletionInstant);
+ deletionInstant, disabledOrigin, legacySuppressedEffects,
+ conditionOverride);
}
+ } else {
+ return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
+ component, configurationActivity, pkg, id, enabler, zenPolicy,
+ zenDeviceEffects, allowManualInvocation, iconResName,
+ triggerDescription, type, userModifiedFields,
+ zenPolicyUserModifiedFields, zenDeviceEffectsUserModifiedFields,
+ deletionInstant);
}
- return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
- component, configurationActivity, pkg, id, enabler, zenPolicy, modified);
}
/** Returns a deep copy of the {@link ZenRule}. */
@@ -2971,7 +2938,7 @@ public class ZenModeConfig implements Parcelable {
}
public boolean isActive() {
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
if (!enabled || getPkg() == null) {
return false;
} else if (conditionOverride == OVERRIDE_ACTIVATE) {
@@ -2989,7 +2956,7 @@ public class ZenModeConfig implements Parcelable {
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
@ConditionOverride
public int getConditionOverride() {
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
return conditionOverride;
} else {
return snoozing ? OVERRIDE_DEACTIVATE : OVERRIDE_NONE;
@@ -2997,7 +2964,7 @@ public class ZenModeConfig implements Parcelable {
}
public void setConditionOverride(@ConditionOverride int value) {
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
conditionOverride = value;
} else {
if (value == OVERRIDE_ACTIVATE) {
@@ -3026,7 +2993,7 @@ public class ZenModeConfig implements Parcelable {
* manual deactivation (which used to be called "snoozing").
*/
public void reconsiderConditionOverride() {
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
if (conditionOverride == OVERRIDE_ACTIVATE && isTrueOrUnknown()) {
resetConditionOverride();
} else if (conditionOverride == OVERRIDE_DEACTIVATE && !isTrueOrUnknown()) {
@@ -3085,11 +3052,8 @@ public class ZenModeConfig implements Parcelable {
& NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) != 0;
boolean allowConversations = (policy.priorityConversationSenders
& Policy.PRIORITY_CATEGORY_CONVERSATIONS) != 0;
- boolean areChannelsBypassingDnd = (policy.state & Policy.STATE_CHANNELS_BYPASSING_DND) != 0;
- if (Flags.modesApi()) {
- areChannelsBypassingDnd = policy.hasPriorityChannels()
- && policy.allowPriorityChannels();
- }
+ boolean areChannelsBypassingDnd =
+ policy.hasPriorityChannels() && policy.allowPriorityChannels();
boolean allowSystem = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_SYSTEM) != 0;
return !allowReminders && !allowCalls && !allowMessages && !allowEvents
&& !allowRepeatCallers && !areChannelsBypassingDnd && !allowSystem
@@ -3129,15 +3093,12 @@ public class ZenModeConfig implements Parcelable {
&& !policy.isCategoryAllowed(PRIORITY_CATEGORY_EVENTS, false)
&& !policy.isCategoryAllowed(PRIORITY_CATEGORY_REPEAT_CALLERS, false)
&& !policy.isCategoryAllowed(PRIORITY_CATEGORY_SYSTEM, false)
- && !(config.areChannelsBypassingDnd && policy.getPriorityChannelsAllowed()
+ && !(config.hasPriorityChannels && policy.getPriorityChannelsAllowed()
== STATE_ALLOW);
} else {
- boolean areChannelsBypassingDnd = config.areChannelsBypassingDnd;
- if (Flags.modesApi()) {
- areChannelsBypassingDnd = config.areChannelsBypassingDnd
- && config.isAllowPriorityChannels();
- }
+ boolean areChannelsBypassingDnd = config.hasPriorityChannels
+ && config.isAllowPriorityChannels();
return !config.isAllowReminders() && !config.isAllowCalls() && !config.isAllowMessages()
&& !config.isAllowEvents() && !config.isAllowRepeatCallers()
&& !areChannelsBypassingDnd && !config.isAllowSystem();
diff --git a/core/java/android/service/notification/ZenModeDiff.java b/core/java/android/service/notification/ZenModeDiff.java
index 31acd248dcc0..c159e4016095 100644
--- a/core/java/android/service/notification/ZenModeDiff.java
+++ b/core/java/android/service/notification/ZenModeDiff.java
@@ -16,7 +16,6 @@
package android.service.notification;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.Flags;
@@ -249,7 +248,7 @@ public class ZenModeDiff {
public static final String FIELD_ALLOW_MESSAGES_FROM = "allowMessagesFrom";
public static final String FIELD_ALLOW_CONVERSATIONS_FROM = "allowConversationsFrom";
public static final String FIELD_SUPPRESSED_VISUAL_EFFECTS = "suppressedVisualEffects";
- public static final String FIELD_ARE_CHANNELS_BYPASSING_DND = "areChannelsBypassingDnd";
+ public static final String FIELD_HAS_PRIORITY_CHANNELS = "hasPriorityChannels";
public static final String FIELD_ALLOW_PRIORITY_CHANNELS = "allowPriorityChannels";
private static final Set<String> PEOPLE_TYPE_FIELDS =
Set.of(FIELD_ALLOW_CALLS_FROM, FIELD_ALLOW_MESSAGES_FROM);
@@ -323,15 +322,13 @@ public class ZenModeDiff {
addField(FIELD_SUPPRESSED_VISUAL_EFFECTS,
new FieldDiff<>(from.suppressedVisualEffects, to.suppressedVisualEffects));
}
- if (from.areChannelsBypassingDnd != to.areChannelsBypassingDnd) {
- addField(FIELD_ARE_CHANNELS_BYPASSING_DND,
- new FieldDiff<>(from.areChannelsBypassingDnd, to.areChannelsBypassingDnd));
+ if (from.hasPriorityChannels != to.hasPriorityChannels) {
+ addField(FIELD_HAS_PRIORITY_CHANNELS,
+ new FieldDiff<>(from.hasPriorityChannels, to.hasPriorityChannels));
}
- if (Flags.modesApi()) {
- if (from.allowPriorityChannels != to.allowPriorityChannels) {
- addField(FIELD_ALLOW_PRIORITY_CHANNELS,
- new FieldDiff<>(from.allowPriorityChannels, to.allowPriorityChannels));
- }
+ if (from.allowPriorityChannels != to.allowPriorityChannels) {
+ addField(FIELD_ALLOW_PRIORITY_CHANNELS,
+ new FieldDiff<>(from.allowPriorityChannels, to.allowPriorityChannels));
}
// Compare automatic and manual rules
@@ -491,7 +488,6 @@ public class ZenModeDiff {
public static final String FIELD_ENABLER = "enabler";
public static final String FIELD_ZEN_POLICY = "zenPolicy";
public static final String FIELD_ZEN_DEVICE_EFFECTS = "zenDeviceEffects";
- public static final String FIELD_MODIFIED = "modified";
public static final String FIELD_PKG = "pkg";
public static final String FIELD_ALLOW_MANUAL = "allowManualInvocation";
public static final String FIELD_ICON_RES = "iconResName";
@@ -532,7 +528,7 @@ public class ZenModeDiff {
if (from.enabled != to.enabled) {
addField(FIELD_ENABLED, new FieldDiff<>(from.enabled, to.enabled));
}
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
if (from.conditionOverride != to.conditionOverride) {
addField(FIELD_CONDITION_OVERRIDE,
new FieldDiff<>(from.conditionOverride, to.conditionOverride));
@@ -572,51 +568,40 @@ public class ZenModeDiff {
if (!Objects.equals(from.enabler, to.enabler)) {
addField(FIELD_ENABLER, new FieldDiff<>(from.enabler, to.enabler));
}
- if (android.app.Flags.modesApi()) {
- PolicyDiff policyDiff = new PolicyDiff(from.zenPolicy, to.zenPolicy);
- if (policyDiff.hasDiff()) {
- addField(FIELD_ZEN_POLICY, new FieldDiff<>(from.zenPolicy, to.zenPolicy,
- policyDiff));
- }
- } else {
- if (!Objects.equals(from.zenPolicy, to.zenPolicy)) {
- addField(FIELD_ZEN_POLICY, new FieldDiff<>(from.zenPolicy, to.zenPolicy));
- }
- }
- if (from.modified != to.modified) {
- addField(FIELD_MODIFIED, new FieldDiff<>(from.modified, to.modified));
+ PolicyDiff policyDiff = new PolicyDiff(from.zenPolicy, to.zenPolicy);
+ if (policyDiff.hasDiff()) {
+ addField(FIELD_ZEN_POLICY, new FieldDiff<>(from.zenPolicy, to.zenPolicy,
+ policyDiff));
}
if (!Objects.equals(from.pkg, to.pkg)) {
addField(FIELD_PKG, new FieldDiff<>(from.pkg, to.pkg));
}
- if (android.app.Flags.modesApi()) {
- DeviceEffectsDiff deviceEffectsDiff = new DeviceEffectsDiff(from.zenDeviceEffects,
- to.zenDeviceEffects);
- if (deviceEffectsDiff.hasDiff()) {
- addField(FIELD_ZEN_DEVICE_EFFECTS,
- new FieldDiff<>(from.zenDeviceEffects, to.zenDeviceEffects,
- deviceEffectsDiff));
- }
- if (!Objects.equals(from.triggerDescription, to.triggerDescription)) {
- addField(FIELD_TRIGGER_DESCRIPTION,
- new FieldDiff<>(from.triggerDescription, to.triggerDescription));
- }
- if (from.type != to.type) {
- addField(FIELD_TYPE, new FieldDiff<>(from.type, to.type));
- }
- if (from.allowManualInvocation != to.allowManualInvocation) {
- addField(FIELD_ALLOW_MANUAL,
- new FieldDiff<>(from.allowManualInvocation, to.allowManualInvocation));
- }
- if (!Objects.equals(from.iconResName, to.iconResName)) {
- addField(FIELD_ICON_RES, new FieldDiff<>(from.iconResName, to.iconResName));
- }
- if (android.app.Flags.modesUi()) {
- if (from.legacySuppressedEffects != to.legacySuppressedEffects) {
- addField(FIELD_LEGACY_SUPPRESSED_EFFECTS,
- new FieldDiff<>(from.legacySuppressedEffects,
- to.legacySuppressedEffects));
- }
+ DeviceEffectsDiff deviceEffectsDiff = new DeviceEffectsDiff(from.zenDeviceEffects,
+ to.zenDeviceEffects);
+ if (deviceEffectsDiff.hasDiff()) {
+ addField(FIELD_ZEN_DEVICE_EFFECTS,
+ new FieldDiff<>(from.zenDeviceEffects, to.zenDeviceEffects,
+ deviceEffectsDiff));
+ }
+ if (!Objects.equals(from.triggerDescription, to.triggerDescription)) {
+ addField(FIELD_TRIGGER_DESCRIPTION,
+ new FieldDiff<>(from.triggerDescription, to.triggerDescription));
+ }
+ if (from.type != to.type) {
+ addField(FIELD_TYPE, new FieldDiff<>(from.type, to.type));
+ }
+ if (from.allowManualInvocation != to.allowManualInvocation) {
+ addField(FIELD_ALLOW_MANUAL,
+ new FieldDiff<>(from.allowManualInvocation, to.allowManualInvocation));
+ }
+ if (!Objects.equals(from.iconResName, to.iconResName)) {
+ addField(FIELD_ICON_RES, new FieldDiff<>(from.iconResName, to.iconResName));
+ }
+ if (android.app.Flags.modesUi()) {
+ if (from.legacySuppressedEffects != to.legacySuppressedEffects) {
+ addField(FIELD_LEGACY_SUPPRESSED_EFFECTS,
+ new FieldDiff<>(from.legacySuppressedEffects,
+ to.legacySuppressedEffects));
}
}
}
@@ -702,7 +687,6 @@ public class ZenModeDiff {
* Diff class representing a change between two
* {@link android.service.notification.ZenDeviceEffects}.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static class DeviceEffectsDiff extends BaseDiff {
public static final String FIELD_GRAYSCALE = "mGrayscale";
public static final String FIELD_SUPPRESS_AMBIENT_DISPLAY = "mSuppressAmbientDisplay";
@@ -843,7 +827,6 @@ public class ZenModeDiff {
/**
* Diff class representing a change between two {@link android.service.notification.ZenPolicy}.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static class PolicyDiff extends BaseDiff {
public static final String FIELD_PRIORITY_CATEGORY_REMINDERS =
"mPriorityCategories_Reminders";
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index 4cff67e24a0f..6b98c4144f91 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -16,13 +16,11 @@
package android.service.notification;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
-import android.app.Flags;
import android.app.Notification;
import android.app.NotificationChannel;
import android.os.Parcel;
@@ -78,91 +76,74 @@ public final class ZenPolicy implements Parcelable {
* the same time.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_MESSAGES = 1 << 0;
/**
* Covers modifications to CALL_SENDERS and PRIORITY_CATEGORY_CALLS, which are set at
* the same time.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_CALLS = 1 << 1;
/**
* Covers modifications to CONVERSATION_SENDERS and PRIORITY_CATEGORY_CONVERSATIONS, which are
* set at the same time.
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_CONVERSATIONS = 1 << 2;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_ALLOW_CHANNELS = 1 << 3;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_PRIORITY_CATEGORY_REMINDERS = 1 << 4;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_PRIORITY_CATEGORY_EVENTS = 1 << 5;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS = 1 << 6;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_PRIORITY_CATEGORY_ALARMS = 1 << 7;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_PRIORITY_CATEGORY_MEDIA = 1 << 8;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_PRIORITY_CATEGORY_SYSTEM = 1 << 9;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT = 1 << 10;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_VISUAL_EFFECT_LIGHTS = 1 << 11;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_VISUAL_EFFECT_PEEK = 1 << 12;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_VISUAL_EFFECT_STATUS_BAR = 1 << 13;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_VISUAL_EFFECT_BADGE = 1 << 14;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_VISUAL_EFFECT_AMBIENT = 1 << 15;
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int FIELD_VISUAL_EFFECT_NOTIFICATION_LIST = 1 << 16;
private List<Integer> mPriorityCategories;
@@ -170,7 +151,6 @@ public final class ZenPolicy implements Parcelable {
private @PeopleType int mPriorityMessages = PEOPLE_TYPE_UNSET;
private @PeopleType int mPriorityCalls = PEOPLE_TYPE_UNSET;
private @ConversationSenders int mConversationSenders = CONVERSATION_SENDERS_UNSET;
- @FlaggedApi(Flags.FLAG_MODES_API)
private @ChannelType int mAllowChannels = CHANNEL_POLICY_UNSET;
/** @hide */
@@ -358,7 +338,6 @@ public final class ZenPolicy implements Parcelable {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int CHANNEL_POLICY_UNSET = 0;
/**
@@ -367,7 +346,6 @@ public final class ZenPolicy implements Parcelable {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int CHANNEL_POLICY_PRIORITY = 1;
/**
@@ -376,7 +354,6 @@ public final class ZenPolicy implements Parcelable {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static final int CHANNEL_POLICY_NONE = 2;
/** @hide */
@@ -386,7 +363,6 @@ public final class ZenPolicy implements Parcelable {
}
/** @hide */
- @FlaggedApi(Flags.FLAG_MODES_API)
public ZenPolicy(List<Integer> priorityCategories, List<Integer> visualEffects,
@PeopleType int priorityMessages, @PeopleType int priorityCalls,
@ConversationSenders int conversationSenders, @ChannelType int allowChannels) {
@@ -409,7 +385,6 @@ public final class ZenPolicy implements Parcelable {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static ZenPolicy getBasePolicyInterruptionFilterAlarms() {
return new ZenPolicy.Builder()
.disallowAllSounds()
@@ -430,7 +405,6 @@ public final class ZenPolicy implements Parcelable {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static ZenPolicy getBasePolicyInterruptionFilterNone() {
return new ZenPolicy.Builder()
.disallowAllSounds()
@@ -628,7 +602,6 @@ public final class ZenPolicy implements Parcelable {
* channels may bypass; if {@link #STATE_DISALLOW}, then even notifications from channels
* with {@link NotificationChannel#canBypassDnd()} will be intercepted.
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public @State int getPriorityChannelsAllowed() {
switch (mAllowChannels) {
case CHANNEL_POLICY_PRIORITY:
@@ -695,14 +668,10 @@ public final class ZenPolicy implements Parcelable {
* Builds the current ZenPolicy.
*/
public @NonNull ZenPolicy build() {
- if (Flags.modesApi()) {
- return new ZenPolicy(new ArrayList<>(mZenPolicy.mPriorityCategories),
- new ArrayList<>(mZenPolicy.mVisualEffects),
- mZenPolicy.mPriorityMessages, mZenPolicy.mPriorityCalls,
- mZenPolicy.mConversationSenders, mZenPolicy.mAllowChannels);
- } else {
- return mZenPolicy.copy();
- }
+ return new ZenPolicy(new ArrayList<>(mZenPolicy.mPriorityCategories),
+ new ArrayList<>(mZenPolicy.mVisualEffects),
+ mZenPolicy.mPriorityMessages, mZenPolicy.mPriorityCalls,
+ mZenPolicy.mConversationSenders, mZenPolicy.mAllowChannels);
}
/**
@@ -1054,7 +1023,6 @@ public final class ZenPolicy implements Parcelable {
* Set whether priority channels are permitted to break through DND.
*/
@SuppressLint("BuilderSetStyle")
- @FlaggedApi(Flags.FLAG_MODES_API)
public @NonNull Builder allowPriorityChannels(boolean allow) {
mZenPolicy.mAllowChannels = allow ? CHANNEL_POLICY_PRIORITY : CHANNEL_POLICY_NONE;
return this;
@@ -1079,38 +1047,21 @@ public final class ZenPolicy implements Parcelable {
dest.writeInt(mPriorityMessages);
dest.writeInt(mPriorityCalls);
dest.writeInt(mConversationSenders);
- if (Flags.modesApi()) {
- dest.writeInt(mAllowChannels);
- }
+ dest.writeInt(mAllowChannels);
}
public static final @NonNull Creator<ZenPolicy> CREATOR =
new Creator<ZenPolicy>() {
@Override
public ZenPolicy createFromParcel(Parcel source) {
- ZenPolicy policy;
- if (Flags.modesApi()) {
- policy = new ZenPolicy(
- trimList(source.readArrayList(Integer.class.getClassLoader(),
- Integer.class), NUM_PRIORITY_CATEGORIES),
- trimList(source.readArrayList(Integer.class.getClassLoader(),
- Integer.class), NUM_VISUAL_EFFECTS),
- source.readInt(), source.readInt(), source.readInt(),
- source.readInt()
+ return new ZenPolicy(
+ trimList(source.readArrayList(Integer.class.getClassLoader(),
+ Integer.class), NUM_PRIORITY_CATEGORIES),
+ trimList(source.readArrayList(Integer.class.getClassLoader(),
+ Integer.class), NUM_VISUAL_EFFECTS),
+ source.readInt(), source.readInt(), source.readInt(),
+ source.readInt()
);
- } else {
- policy = new ZenPolicy();
- policy.mPriorityCategories =
- trimList(source.readArrayList(Integer.class.getClassLoader(),
- Integer.class), NUM_PRIORITY_CATEGORIES);
- policy.mVisualEffects =
- trimList(source.readArrayList(Integer.class.getClassLoader(),
- Integer.class), NUM_VISUAL_EFFECTS);
- policy.mPriorityMessages = source.readInt();
- policy.mPriorityCalls = source.readInt();
- policy.mConversationSenders = source.readInt();
- }
- return policy;
}
@Override
@@ -1121,18 +1072,16 @@ public final class ZenPolicy implements Parcelable {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder(ZenPolicy.class.getSimpleName())
+ return new StringBuilder(ZenPolicy.class.getSimpleName())
.append('{')
.append("priorityCategories=[").append(priorityCategoriesToString())
.append("], visualEffects=[").append(visualEffectsToString())
.append("], priorityCallsSenders=").append(peopleTypeToString(mPriorityCalls))
.append(", priorityMessagesSenders=").append(peopleTypeToString(mPriorityMessages))
.append(", priorityConversationSenders=").append(
- conversationTypeToString(mConversationSenders));
- if (Flags.modesApi()) {
- sb.append(", allowChannels=").append(channelTypeToString(mAllowChannels));
- }
- return sb.append('}').toString();
+ conversationTypeToString(mConversationSenders))
+ .append(", allowChannels=").append(channelTypeToString(mAllowChannels))
+ .append('}').toString();
}
/** @hide */
@@ -1325,7 +1274,6 @@ public final class ZenPolicy implements Parcelable {
/**
* @hide
*/
- @FlaggedApi(Flags.FLAG_MODES_API)
public static String channelTypeToString(@ChannelType int channelType) {
switch (channelType) {
case CHANNEL_POLICY_UNSET:
@@ -1344,25 +1292,18 @@ public final class ZenPolicy implements Parcelable {
if (o == this) return true;
final ZenPolicy other = (ZenPolicy) o;
- boolean eq = Objects.equals(other.mPriorityCategories, mPriorityCategories)
+ return Objects.equals(other.mPriorityCategories, mPriorityCategories)
&& Objects.equals(other.mVisualEffects, mVisualEffects)
&& other.mPriorityCalls == mPriorityCalls
&& other.mPriorityMessages == mPriorityMessages
- && other.mConversationSenders == mConversationSenders;
- if (Flags.modesApi()) {
- return eq && other.mAllowChannels == mAllowChannels;
- }
- return eq;
+ && other.mConversationSenders == mConversationSenders
+ && other.mAllowChannels == mAllowChannels;
}
@Override
public int hashCode() {
- if (Flags.modesApi()) {
- return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls,
- mPriorityMessages, mConversationSenders, mAllowChannels);
- }
- return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, mPriorityMessages,
- mConversationSenders);
+ return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls,
+ mPriorityMessages, mConversationSenders, mAllowChannels);
}
private @State int getZenPolicyPriorityCategoryState(@PriorityCategory int
@@ -1480,13 +1421,10 @@ public final class ZenPolicy implements Parcelable {
}
}
- // apply allowed channels
- if (Flags.modesApi()) {
- // if no channels are allowed, can't newly allow them
- if (mAllowChannels != CHANNEL_POLICY_NONE
- && policyToApply.mAllowChannels != CHANNEL_POLICY_UNSET) {
- mAllowChannels = policyToApply.mAllowChannels;
- }
+ // apply allowed channels -> if no channels are allowed, can't newly allow them
+ if (mAllowChannels != CHANNEL_POLICY_NONE
+ && policyToApply.mAllowChannels != CHANNEL_POLICY_UNSET) {
+ mAllowChannels = policyToApply.mAllowChannels;
}
}
@@ -1499,7 +1437,6 @@ public final class ZenPolicy implements Parcelable {
* @hide
*/
@TestApi
- @FlaggedApi(Flags.FLAG_MODES_API)
public @NonNull ZenPolicy overwrittenWith(@Nullable ZenPolicy newPolicy) {
ZenPolicy result = this.copy();
@@ -1596,10 +1533,7 @@ public final class ZenPolicy implements Parcelable {
proto.write(DNDPolicyProto.ALLOW_CALLS_FROM, getPriorityCallSenders());
proto.write(DNDPolicyProto.ALLOW_MESSAGES_FROM, getPriorityMessageSenders());
proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, getPriorityConversationSenders());
-
- if (Flags.modesApi()) {
- proto.write(DNDPolicyProto.ALLOW_CHANNELS, getPriorityChannelsAllowed());
- }
+ proto.write(DNDPolicyProto.ALLOW_CHANNELS, getPriorityChannelsAllowed());
proto.flush();
return bytes.toByteArray();
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 464756842caf..41a64e22e058 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1595,8 +1595,17 @@ public abstract class WallpaperService extends Service {
mWindow.setSession(mSession);
mLayout.packageName = getPackageName();
- mIWallpaperEngine.mDisplayManager.registerDisplayListener(mDisplayListener,
- mCaller.getHandler());
+ if (com.android.server.display.feature.flags.Flags
+ .displayListenerPerformanceImprovements()
+ && com.android.server.display.feature.flags.Flags
+ .committedStateSeparateEvent()) {
+ mIWallpaperEngine.mDisplayManager.registerDisplayListener(mDisplayListener,
+ mCaller.getHandler(), DisplayManager.EVENT_TYPE_DISPLAY_CHANGED,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_COMMITTED_STATE_CHANGED);
+ } else {
+ mIWallpaperEngine.mDisplayManager.registerDisplayListener(mDisplayListener,
+ mCaller.getHandler());
+ }
mDisplay = mIWallpaperEngine.mDisplay;
// Use window context of TYPE_WALLPAPER so client can access UI resources correctly.
mDisplayContext = createDisplayContext(mDisplay)
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 323d83b92143..2fa56137a8a0 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -672,7 +672,7 @@ public abstract class Layout {
// LINT.IfChange(hct_darken)
var lab = new double[3];
ColorUtils.colorToLAB(color, lab);
- return lab[0] < 50.0;
+ return lab[0] <= 50.0;
// LINT.ThenChange(/libs/hwui/hwui/DrawTextFunctor.h:hct_darken)
}
@@ -1021,6 +1021,12 @@ public abstract class Layout {
return;
}
+ if (!mSpannedText || mSpanColors == null) {
+ if (mPaint.getAlpha() == 0) {
+ return;
+ }
+ }
+
var padding = Math.max(HIGH_CONTRAST_TEXT_BORDER_WIDTH_MIN_PX,
mPaint.getTextSize() * HIGH_CONTRAST_TEXT_BORDER_WIDTH_FACTOR);
var cornerRadius = mPaint.density * HIGH_CONTRAST_TEXT_BACKGROUND_CORNER_RADIUS_DP;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index ca0959af3ff8..231aa6816908 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1599,7 +1599,6 @@ public final class Display {
mGlobal.registerDisplayListener(toRegister, executor,
DisplayManagerGlobal
.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED
- | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE
| DisplayManagerGlobal
.INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED,
ActivityThread.currentPackageName());
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index ecdbaa3cd2f4..d880072aa404 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -44,6 +44,7 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.display.BrightnessSynchronizer;
+import com.android.server.display.feature.flags.Flags;
import java.util.Arrays;
import java.util.Objects;
@@ -447,18 +448,20 @@ public final class DisplayInfo implements Parcelable {
}
public boolean equals(DisplayInfo other) {
- return equals(other, /* compareRefreshRate */ true);
+ return equals(other, /* compareOnlyBasicChanges */ false);
}
/**
* Compares if the two DisplayInfo objects are equal or not
* @param other The other DisplayInfo against which the comparison is to be done
- * @param compareRefreshRate Indicates if the refresh rate is also to be considered in
- * comparison
+ * @param compareOnlyBasicChanges Indicates if the changes to be compared are the ones which
+ * could lead to an emission of
+ * {@link android.hardware.display.DisplayManager.EVENT_TYPE_DISPLAY_CHANGED}
+ * event
* @return
*/
- public boolean equals(DisplayInfo other, boolean compareRefreshRate) {
- boolean isEqualWithoutRefreshRate = other != null
+ public boolean equals(DisplayInfo other, boolean compareOnlyBasicChanges) {
+ boolean isEqualWithOnlyBasicChanges = other != null
&& layerStack == other.layerStack
&& flags == other.flags
&& type == other.type
@@ -494,7 +497,6 @@ public final class DisplayInfo implements Parcelable {
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
&& state == other.state
- && committedState == other.committedState
&& ownerUid == other.ownerUid
&& Objects.equals(ownerPackageName, other.ownerPackageName)
&& removeMode == other.removeMode
@@ -512,14 +514,19 @@ public final class DisplayInfo implements Parcelable {
thermalBrightnessThrottlingDataId, other.thermalBrightnessThrottlingDataId)
&& canHostTasks == other.canHostTasks;
- if (compareRefreshRate) {
- return isEqualWithoutRefreshRate
+ if (!Flags.committedStateSeparateEvent()) {
+ isEqualWithOnlyBasicChanges = isEqualWithOnlyBasicChanges
+ && (committedState == other.committedState);
+ }
+ if (!compareOnlyBasicChanges) {
+ return isEqualWithOnlyBasicChanges
&& (getRefreshRate() == other.getRefreshRate())
&& appVsyncOffsetNanos == other.appVsyncOffsetNanos
&& presentationDeadlineNanos == other.presentationDeadlineNanos
- && (modeId == other.modeId);
+ && (modeId == other.modeId)
+ && (committedState == other.committedState);
}
- return isEqualWithoutRefreshRate;
+ return isEqualWithOnlyBasicChanges;
}
@Override
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 73cd5ecd39ef..df680c054f56 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -32,7 +32,6 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
-import android.util.TypedValue;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.RemoteViews;
@@ -266,20 +265,14 @@ public class NotificationHeaderView extends RelativeLayout {
? R.style.TextAppearance_DeviceDefault_Notification_Title
: R.style.TextAppearance_DeviceDefault_Notification_Info;
// Most of the time, we're showing text in the minimized state
- if (findViewById(R.id.header_text) instanceof TextView headerText) {
- headerText.setTextAppearance(styleResId);
- if (notificationsRedesignTemplates()) {
- // TODO: b/378660052 - When inlining the redesign flag, this should be updated
- // directly in TextAppearance_DeviceDefault_Notification_Title so we won't need to
- // override it here.
- float textSize = getContext().getResources().getDimension(
- R.dimen.notification_2025_title_text_size);
- headerText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
- }
+ View headerText = findViewById(R.id.header_text);
+ if (headerText instanceof TextView) {
+ ((TextView) headerText).setTextAppearance(styleResId);
}
// If there's no summary or text, we show the app name instead of nothing
- if (findViewById(R.id.app_name_text) instanceof TextView appNameText) {
- appNameText.setTextAppearance(styleResId);
+ View appNameText = findViewById(R.id.app_name_text);
+ if (appNameText instanceof TextView) {
+ ((TextView) appNameText).setTextAppearance(styleResId);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 80b4f2caabbb..6b6147a3749d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -118,6 +118,7 @@ import static android.view.flags.Flags.addSchandleToVriSurface;
import static android.view.flags.Flags.disableDrawWakeLock;
import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
+import static android.view.flags.Flags.toolkitFrameRateDebug;
import static android.view.flags.Flags.toolkitFrameRateFunctionEnablingReadOnly;
import static android.view.flags.Flags.toolkitFrameRateTouchBoost25q1;
import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly;
@@ -538,6 +539,11 @@ public final class ViewRootImpl implements ViewParent,
private static boolean sAlwaysAssignFocus;
/**
+ * whether we pre-initialized the Buffer Allocator
+ */
+ private static boolean sPreInitializedBufferAllocator = false;
+
+ /**
* This list must only be modified by the main thread.
*/
final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
@@ -1222,6 +1228,7 @@ public final class ViewRootImpl implements ViewParent,
com.android.graphics.surfaceflinger.flags.Flags.vrrBugfix24q4();
private static final boolean sEnableVrr = ViewProperties.vrr_enabled().orElse(true);
private static final boolean sToolkitInitialTouchBoostFlagValue = toolkitInitialTouchBoost();
+ private static boolean sToolkitFrameRateDebugFlagValue = toolkitFrameRateDebug();
static {
sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
@@ -1342,6 +1349,11 @@ public final class ViewRootImpl implements ViewParent,
com.android.server.display.feature.flags.Flags.subscribeGranularDisplayEvents();
mSendPerfHintOnTouch = adpfViewrootimplActionDownBoost();
+
+ if (!sPreInitializedBufferAllocator) {
+ preInitBufferAllocator();
+ sPreInitializedBufferAllocator = true;
+ }
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -13129,6 +13141,11 @@ public final class ViewRootImpl implements ViewParent,
if (sToolkitFrameRateFunctionEnablingReadOnlyFlagValue) {
mFrameRateTransaction.setFrameRateCategory(mSurfaceControl,
frameRateCategory, false).applyAsyncUnsafe();
+
+ if (sToolkitFrameRateDebugFlagValue) {
+ Log.v(mTag, "### ViewRootImpl setFrameRateCategory '"
+ + categoryToString(frameRateCategory) + "'");
+ }
}
mLastPreferredFrameRateCategory = frameRateCategory;
}
@@ -13191,8 +13208,15 @@ public final class ViewRootImpl implements ViewParent,
if (preferredFrameRate > 0) {
mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate,
mFrameRateCompatibility);
+ if (sToolkitFrameRateDebugFlagValue) {
+ Log.v(mTag, "### ViewRootImpl setFrameRate '"
+ + preferredFrameRate + "'");
+ }
} else {
mFrameRateTransaction.clearFrameRate(mSurfaceControl);
+ if (sToolkitFrameRateDebugFlagValue) {
+ Log.v(mTag, "### ViewRootImpl setFrameRate 0 Hz");
+ }
}
mFrameRateTransaction.applyAsyncUnsafe();
}
@@ -13246,6 +13270,12 @@ public final class ViewRootImpl implements ViewParent,
// mFrameRateCategoryView = view == null ? "-" : view.getClass().getSimpleName();
}
mDrawnThisFrame = true;
+
+ if (sToolkitFrameRateDebugFlagValue) {
+ String viewName = view == null ? "-" : view.getClass().getSimpleName();
+ Log.v(mTag, "### View: " + viewName + " votes '"
+ + categoryToString(frameRateCategory) + "'");
+ }
}
/**
@@ -13562,4 +13592,10 @@ public final class ViewRootImpl implements ViewParent,
sProtoLogInitialized = true;
}
}
+
+ private void preInitBufferAllocator() {
+ if (com.android.graphics.hwui.flags.Flags.earlyPreinitBufferAllocator()) {
+ ThreadedRenderer.preInitBufferAllocator();
+ }
+ }
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index db699d7bfb06..93eed370004b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -625,12 +625,6 @@ public interface WindowManager extends ViewManager {
int TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH = (1 << 14); // 0x4000
/**
- * Transition flag: Indicates that aod is showing hidden by entering doze
- * @hide
- */
- int TRANSIT_FLAG_AOD_APPEARING = (1 << 15); // 0x8000
-
- /**
* @hide
*/
@IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = {
@@ -649,7 +643,6 @@ public interface WindowManager extends ViewManager {
TRANSIT_FLAG_KEYGUARD_OCCLUDING,
TRANSIT_FLAG_KEYGUARD_UNOCCLUDING,
TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH,
- TRANSIT_FLAG_AOD_APPEARING,
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionFlags {}
@@ -666,8 +659,7 @@ public interface WindowManager extends ViewManager {
(TRANSIT_FLAG_KEYGUARD_GOING_AWAY
| TRANSIT_FLAG_KEYGUARD_APPEARING
| TRANSIT_FLAG_KEYGUARD_OCCLUDING
- | TRANSIT_FLAG_KEYGUARD_UNOCCLUDING
- | TRANSIT_FLAG_AOD_APPEARING);
+ | TRANSIT_FLAG_KEYGUARD_UNOCCLUDING);
/**
* Remove content mode: Indicates remove content mode is currently not defined.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 578b7b6a63fa..ede0b3cf8cce 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -2684,9 +2684,10 @@ public class AccessibilityNodeInfo implements Parcelable {
* <p><b>Note:</b> The start and end {@link SelectionPosition} of the provided {@link Selection}
* should be constructed with {@code this} node or a descendant of it.
*
- * <p><b>Note:</b> {@link AccessibilityNodeInfo#setFocusable} and {@link
- * AccessibilityNodeInfo#setFocused} should both be called with {@code true} before setting the
- * selection in order to make {@code this} node a candidate to contain a selection.
+ * <p><b>Note:</b> {@link AccessibilityNodeInfo#setFocusable} and
+ * {@link AccessibilityNodeInfo#setFocused} should both be called with {@code true}
+ * before setting the selection in order to make {@code this} node a candidate to
+ * contain a selection.
*
* <p><b>Note:</b> Cannot be called from an AccessibilityService. This class is made immutable
* before being delivered to an AccessibilityService.
@@ -2706,12 +2707,10 @@ public class AccessibilityNodeInfo implements Parcelable {
* Gets the extended selection, which is a representation of selection that spans multiple nodes
* that exist within the subtree of the node defining selection.
*
- * <p><b>Note:</b> The start and end {@link SelectionPosition} of the provided {@link Selection}
- * should be constructed with {@code this} node or a descendant of it.
- *
- * <p><b>Note:</b> In order for a node to be a candidate to contain a selection, {@link
- * AccessibilityNodeInfo#isFocusable()} ()} and {@link AccessibilityNodeInfo#isFocused()} should
- * both be return with {@code true}.
+ * <p><b>Note:</b> Nodes that are candidates to contain a selection should return
+ * {@code true} from {@link #isFocusable()} and {@link #isFocused()}.
+ * The start and end {@link SelectionPosition}s of this {@link Selection}
+ * should exist within {@code this} node or its descendants.
*
* @return The extended selection within the node's subtree, or {@code null} if no selection
* exists.
@@ -5840,8 +5839,8 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Instantiates a new SelectionPosition.
*
- * @param view The {@link View} containing the virtual descendant associated with the
- * selection position.
+ * @param view The {@link View} containing the text associated with this selection
+ * position.
* @param offset The offset for a selection position within {@code view}'s text content,
* which should be a value between 0 and the length of {@code view}'s text.
*/
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index 3bc2205f8e1c..18fa0f353f36 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -143,4 +143,11 @@ flag {
namespace: "toolkit"
description: "Feature flag to update initial touch boost logic"
bug: "393004744"
+}
+
+flag {
+ name: "toolkit_frame_rate_debug"
+ namespace: "toolkit"
+ description: "Feature flag to ennable ARR debug message"
+ bug: "394614443"
} \ No newline at end of file
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 0f5476f58f74..0a5c14e3a08b 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -8565,12 +8565,16 @@ public class RemoteViews implements Parcelable, Filter {
return context;
}
try {
- // Use PackageManager as the source of truth for application information, rather
- // than the parceled ApplicationInfo provided by the app.
- ApplicationInfo sanitizedApplication =
- context.getPackageManager().getApplicationInfoAsUser(
- mApplication.packageName, 0,
- UserHandle.getUserId(mApplication.uid));
+ ApplicationInfo sanitizedApplication = mApplication;
+ try {
+ // Use PackageManager as the source of truth for application information, rather
+ // than the parceled ApplicationInfo provided by the app.
+ sanitizedApplication = context.getPackageManager().getApplicationInfoAsUser(
+ mApplication.packageName, 0, UserHandle.getUserId(mApplication.uid));
+ } catch(SecurityException se) {
+ Log.d(LOG_TAG, "Unable to fetch appInfo for " + mApplication.packageName);
+ }
+
Context applicationContext = context.createApplicationContext(
sanitizedApplication,
Context.CONTEXT_RESTRICTED);
diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java
index 1ce5df7cd137..ca1017b72854 100644
--- a/core/java/android/window/DesktopModeFlags.java
+++ b/core/java/android/window/DesktopModeFlags.java
@@ -57,6 +57,8 @@ public enum DesktopModeFlags {
true),
ENABLE_DESKTOP_CLOSE_SHORTCUT_BUGFIX(Flags::enableDesktopCloseShortcutBugfix, false),
ENABLE_DESKTOP_COMPAT_UI_VISIBILITY_STATUS(Flags::enableCompatUiVisibilityStatus, true),
+ ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX(
+ Flags::enableDesktopIndicatorInSeparateThreadBugfix, false),
ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX(
Flags::enableDesktopRecentsTransitionsCornersBugfix, false),
ENABLE_DESKTOP_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE_BUGFIX(
@@ -94,6 +96,7 @@ public enum DesktopModeFlags {
ENABLE_DESKTOP_WINDOWING_TASK_LIMIT(Flags::enableDesktopWindowingTaskLimit, true),
ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY(Flags::enableDesktopWindowingWallpaperActivity,
true),
+ ENABLE_DRAG_RESIZE_SET_UP_IN_BG_THREAD(Flags::enableDragResizeSetUpInBgThread, false),
ENABLE_FULLY_IMMERSIVE_IN_DESKTOP(Flags::enableFullyImmersiveInDesktop, true),
ENABLE_HANDLE_INPUT_FIX(Flags::enableHandleInputFix, true),
ENABLE_HOLD_TO_DRAG_APP_HANDLE(Flags::enableHoldToDragAppHandle, true),
diff --git a/core/java/android/window/TaskFragmentOperation.java b/core/java/android/window/TaskFragmentOperation.java
index 9d0ea547e734..1fd79ccf9e3f 100644
--- a/core/java/android/window/TaskFragmentOperation.java
+++ b/core/java/android/window/TaskFragmentOperation.java
@@ -90,26 +90,6 @@ public final class TaskFragmentOperation implements Parcelable {
public static final int OP_TYPE_SET_ISOLATED_NAVIGATION = 11;
/**
- * Reorders the TaskFragment to be the bottom-most in the Task. Note that this op will bring the
- * TaskFragment to the bottom of the Task below all the other Activities and TaskFragments.
- *
- * This is only allowed for system organizers. See
- * {@link com.android.server.wm.TaskFragmentOrganizerController#registerOrganizer(
- * ITaskFragmentOrganizer, boolean)}
- */
- public static final int OP_TYPE_REORDER_TO_BOTTOM_OF_TASK = 12;
-
- /**
- * Reorders the TaskFragment to be the top-most in the Task. Note that this op will bring the
- * TaskFragment to the top of the Task above all the other Activities and TaskFragments.
- *
- * This is only allowed for system organizers. See
- * {@link com.android.server.wm.TaskFragmentOrganizerController#registerOrganizer(
- * ITaskFragmentOrganizer, boolean)}
- */
- public static final int OP_TYPE_REORDER_TO_TOP_OF_TASK = 13;
-
- /**
* Creates a decor surface in the parent Task of the TaskFragment. The created decor surface
* will be provided in {@link TaskFragmentTransaction#TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED}
* event callback. If a decor surface already exists in the parent Task, the current
@@ -118,27 +98,17 @@ public final class TaskFragmentOperation implements Parcelable {
*
* The decor surface can be used to draw the divider between TaskFragments or other decorations.
*/
- public static final int OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE = 14;
+ public static final int OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE = 12;
/**
* Removes the decor surface in the parent Task of the TaskFragment.
*/
- public static final int OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE = 15;
+ public static final int OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE = 13;
/**
* Applies dimming on the parent Task which could cross two TaskFragments.
*/
- public static final int OP_TYPE_SET_DIM_ON_TASK = 16;
-
- /**
- * Sets this TaskFragment to move to bottom of the Task if any of the activities below it is
- * launched in a mode requiring clear top.
- *
- * This is only allowed for system organizers. See
- * {@link com.android.server.wm.TaskFragmentOrganizerController#registerOrganizer(
- * ITaskFragmentOrganizer, boolean)}
- */
- public static final int OP_TYPE_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH = 17;
+ public static final int OP_TYPE_SET_DIM_ON_TASK = 14;
/**
* Sets whether the decor surface will be boosted. When not boosted, the decor surface is placed
@@ -147,7 +117,7 @@ public final class TaskFragmentOperation implements Parcelable {
* surface is placed above all the non-boosted windows in the Task, the content of these
* non-boosted windows will be hidden and inputs are disabled.
*/
- public static final int OP_TYPE_SET_DECOR_SURFACE_BOOSTED = 18;
+ public static final int OP_TYPE_SET_DECOR_SURFACE_BOOSTED = 15;
/**
* Sets the TaskFragment to be pinned.
@@ -159,7 +129,44 @@ public final class TaskFragmentOperation implements Parcelable {
* <p>
* See {@link #OP_TYPE_REORDER_TO_FRONT} on how to reorder a pinned TaskFragment to the top.
*/
- public static final int OP_TYPE_SET_PINNED = 19;
+ public static final int OP_TYPE_SET_PINNED = 16;
+
+ /**
+ * The start index of the privileged operations. Only system organizers are allowed to use
+ * operations with index greater than or equal to this value.
+ */
+ public static final int PRIVILEGED_OP_START = 1000;
+
+ /**
+ * Reorders the TaskFragment to be the bottom-most in the Task. Note that this op will bring the
+ * TaskFragment to the bottom of the Task below all the other Activities and TaskFragments.
+ *
+ * This is only allowed for system organizers. See
+ * {@link com.android.server.wm.TaskFragmentOrganizerController#registerOrganizer(
+ * ITaskFragmentOrganizer, boolean)}
+ */
+ public static final int OP_TYPE_PRIVILEGED_REORDER_TO_BOTTOM_OF_TASK = PRIVILEGED_OP_START + 1;
+
+ /**
+ * Reorders the TaskFragment to be the top-most in the Task. Note that this op will bring the
+ * TaskFragment to the top of the Task above all the other Activities and TaskFragments.
+ *
+ * This is only allowed for system organizers. See
+ * {@link com.android.server.wm.TaskFragmentOrganizerController#registerOrganizer(
+ * ITaskFragmentOrganizer, boolean)}
+ */
+ public static final int OP_TYPE_PRIVILEGED_REORDER_TO_TOP_OF_TASK = PRIVILEGED_OP_START + 2;
+
+ /**
+ * Sets this TaskFragment to move to bottom of the Task if any of the activities below it is
+ * launched in a mode requiring clear top.
+ *
+ * This is only allowed for system organizers. See
+ * {@link com.android.server.wm.TaskFragmentOrganizerController#registerOrganizer(
+ * ITaskFragmentOrganizer, boolean)}
+ */
+ public static final int OP_TYPE_PRIVILEGED_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH =
+ PRIVILEGED_OP_START + 3;
/**
* Sets whether this TaskFragment can affect system UI flags such as the status bar. Default
@@ -169,7 +176,8 @@ public final class TaskFragmentOperation implements Parcelable {
* {@link com.android.server.wm.TaskFragmentOrganizerController#registerOrganizer(
* ITaskFragmentOrganizer, boolean)}
*/
- public static final int OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS = 20;
+ public static final int OP_TYPE_PRIVILEGED_SET_CAN_AFFECT_SYSTEM_UI_FLAGS =
+ PRIVILEGED_OP_START + 4;
@IntDef(prefix = { "OP_TYPE_" }, value = {
OP_TYPE_UNKNOWN,
@@ -185,15 +193,15 @@ public final class TaskFragmentOperation implements Parcelable {
OP_TYPE_SET_RELATIVE_BOUNDS,
OP_TYPE_REORDER_TO_FRONT,
OP_TYPE_SET_ISOLATED_NAVIGATION,
- OP_TYPE_REORDER_TO_BOTTOM_OF_TASK,
- OP_TYPE_REORDER_TO_TOP_OF_TASK,
OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE,
OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE,
OP_TYPE_SET_DIM_ON_TASK,
- OP_TYPE_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH,
OP_TYPE_SET_DECOR_SURFACE_BOOSTED,
OP_TYPE_SET_PINNED,
- OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS,
+ OP_TYPE_PRIVILEGED_REORDER_TO_BOTTOM_OF_TASK,
+ OP_TYPE_PRIVILEGED_REORDER_TO_TOP_OF_TASK,
+ OP_TYPE_PRIVILEGED_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH,
+ OP_TYPE_PRIVILEGED_SET_CAN_AFFECT_SYSTEM_UI_FLAGS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface OperationType {}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index cf21e50e0a19..4f34aa36a204 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -29,7 +29,6 @@ import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_NONE;
@@ -406,8 +405,7 @@ public final class TransitionInfo implements Parcelable {
*/
public boolean hasChangesOrSideEffects() {
return !mChanges.isEmpty() || isKeyguardGoingAway()
- || (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0
- || (mFlags & TRANSIT_FLAG_AOD_APPEARING) != 0;
+ || (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0;
}
/**
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index b805ac560b8d..79120b22c205 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -79,6 +79,16 @@ flag {
}
flag {
+ name: "enable_drag_resize_set_up_in_bg_thread"
+ namespace: "lse_desktop_experience"
+ description: "Enables setting up the drag-resize input listener in a bg thread"
+ bug: "396445663"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_desktop_windowing_wallpaper_activity"
namespace: "lse_desktop_experience"
description: "Enables desktop wallpaper activity to show wallpaper in the desktop mode"
@@ -165,6 +175,16 @@ flag {
}
flag {
+ name: "enable_camera_compat_track_task_and_app_bugfix"
+ namespace: "lse_desktop_experience"
+ description: "Whether to use taskId and app process to track camera apps, and notify the policies only on first camera open and final close"
+ bug: "380840084"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_task_stack_observer_in_shell"
namespace: "lse_desktop_experience"
description: "Introduces a new observer in shell to track the task stack."
@@ -623,6 +643,13 @@ flag {
}
flag {
+ name: "enable_multi_display_split"
+ namespace: "lse_desktop_experience"
+ description: "Enables split screen on multiple displays at the same time"
+ bug: "395943397"
+}
+
+flag {
name: "exclude_caption_from_app_bounds"
namespace: "lse_desktop_experience"
description: "Whether caption insets are excluded from app bounds in freeform"
@@ -706,3 +733,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_desktop_indicator_in_separate_thread_bugfix"
+ namespace: "lse_desktop_experience"
+ description: "Enables running visual indicator view operations in ShellDesktopThread."
+ bug: "366413536"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 52f18fb80c27..0bba24d4ce19 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -20,3 +20,6 @@ per-file *VisualQuery* = file:/core/java/android/service/voice/OWNERS
# System language settings
per-file *Locale* = file:platform/packages/apps/Settings:/src/com/android/settings/localepicker/OWNERS
+
+# Media
+per-file *MediaRoute* = file:/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 9085bbec949f..41e2ca9cdfad 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -816,7 +816,7 @@ public class Cuj {
case CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK:
return "LAUNCHER_WORK_UTILITY_VIEW_SHRINK";
case CUJ_DEFAULT_TASK_TO_TASK_ANIMATION:
- return "CUJ_DEFAULT_TASK_TO_TASK_ANIMATION";
+ return "DEFAULT_TASK_TO_TASK_ANIMATION";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
index 21d000dc5224..b57acf3d97fd 100644
--- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
+++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
@@ -226,6 +226,21 @@ public class AconfigFlags {
}
private Boolean getFlagValueFromNewStorage(String flagPackageAndName) {
+ // We still need to check mFlagValues in case addFlagValuesForTesting() was called for
+ // testing purposes.
+ if (!mFlagValues.isEmpty() && mFlagValues.containsKey(flagPackageAndName)) {
+ Boolean value = mFlagValues.get(flagPackageAndName);
+ if (DEBUG) {
+ Slog.v(
+ LOG_TAG,
+ "Aconfig flag value (FOR TESTING) for "
+ + flagPackageAndName
+ + " = "
+ + value);
+ }
+ return value;
+ }
+
int index = flagPackageAndName.lastIndexOf('.');
if (index < 0) {
Slog.e(LOG_TAG, "Unable to parse package name from " + flagPackageAndName);
diff --git a/core/java/com/android/internal/protolog/IProtoLogConfigurationService.aidl b/core/java/com/android/internal/protolog/IProtoLogConfigurationService.aidl
index 9b60f49d1446..a6f0b306f4bf 100644
--- a/core/java/com/android/internal/protolog/IProtoLogConfigurationService.aidl
+++ b/core/java/com/android/internal/protolog/IProtoLogConfigurationService.aidl
@@ -40,12 +40,12 @@ import com.android.internal.protolog.IProtoLogClient;
*
* {@hide}
*/
-oneway interface IProtoLogConfigurationService {
- interface IRegisterClientArgs {
- String[] getGroups();
- boolean[] getGroupsDefaultLogcatStatus();
- String getViewerConfigFile();
+interface IProtoLogConfigurationService {
+ parcelable RegisterClientArgs {
+ String[] groups;
+ boolean[] groupsDefaultLogcatStatus;
+ String viewerConfigFile;
}
- void registerClient(IProtoLogClient client, IRegisterClientArgs args);
+ oneway void registerClient(IProtoLogClient client, in RegisterClientArgs args);
} \ No newline at end of file
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index d8cf258e23ba..93be3b02a12a 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -62,7 +62,7 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogConfigurationServiceImpl.RegisterClientArgs;
+import com.android.internal.protolog.IProtoLogConfigurationService.RegisterClientArgs;
import com.android.internal.protolog.common.ILogger;
import com.android.internal.protolog.common.IProtoLog;
import com.android.internal.protolog.common.IProtoLogGroup;
@@ -164,11 +164,15 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
try {
var args = createConfigurationServiceRegisterClientArgs();
- final var groupArgs = mLogGroups.values().stream()
- .map(group -> new RegisterClientArgs
- .GroupConfig(group.name(), group.isLogToLogcat()))
- .toArray(RegisterClientArgs.GroupConfig[]::new);
- args.setGroups(groupArgs);
+ args.groups = new String[mLogGroups.size()];
+ args.groupsDefaultLogcatStatus = new boolean[mLogGroups.size()];
+
+ var groups = mLogGroups.values().stream().toList();
+ for (var i = 0; i < groups.size(); i++) {
+ var group = groups.get(i);
+ args.groups[i] = group.name();
+ args.groupsDefaultLogcatStatus[i] = group.isLogToLogcat();
+ }
mConfigurationService.registerClient(this, args);
} catch (RemoteException e) {
diff --git a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
index 1f9df3cc842a..d9c54d695a87 100644
--- a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
@@ -22,7 +22,7 @@ import android.os.ServiceManager;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogConfigurationServiceImpl.RegisterClientArgs;
+import com.android.internal.protolog.IProtoLogConfigurationService.RegisterClientArgs;
import com.android.internal.protolog.common.ILogger;
import com.android.internal.protolog.common.IProtoLogGroup;
@@ -104,8 +104,9 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
@NonNull
@Override
protected RegisterClientArgs createConfigurationServiceRegisterClientArgs() {
- return new RegisterClientArgs()
- .setViewerConfigFile(mViewerConfigFilePath);
+ var args = new RegisterClientArgs();
+ args.viewerConfigFile = mViewerConfigFilePath;
+ return args;
}
/**
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
index 23f7c2a3d987..f83359dddfcc 100644
--- a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
@@ -134,74 +134,6 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
mDataSource = datasource;
}
- public static class RegisterClientArgs extends IRegisterClientArgs.Stub {
- /**
- * The viewer config file to be registered for this client ProtoLog process.
- */
- @Nullable
- private String mViewerConfigFile = null;
- /**
- * The list of all groups that this client protolog process supports and might trace.
- */
- @NonNull
- private String[] mGroups = new String[0];
- /**
- * The default logcat status of the ProtoLog client. True is logging to logcat, false
- * otherwise. The indices should match the indices in {@link mGroups}.
- */
- @NonNull
- private boolean[] mLogcatStatus = new boolean[0];
-
- public record GroupConfig(@NonNull String group, boolean logToLogcat) {}
-
- /**
- * Specify groups to register with this client that will be used for protologging in this
- * process.
- * @param groups to register with this client.
- * @return self
- */
- public RegisterClientArgs setGroups(GroupConfig... groups) {
- mGroups = new String[groups.length];
- mLogcatStatus = new boolean[groups.length];
-
- for (int i = 0; i < groups.length; i++) {
- mGroups[i] = groups[i].group;
- mLogcatStatus[i] = groups[i].logToLogcat;
- }
-
- return this;
- }
-
- /**
- * Set the viewer config file that the logs in this process are using.
- * @param viewerConfigFile The file path of the viewer config.
- * @return self
- */
- public RegisterClientArgs setViewerConfigFile(@NonNull String viewerConfigFile) {
- mViewerConfigFile = viewerConfigFile;
-
- return this;
- }
-
- @Override
- @NonNull
- public String[] getGroups() {
- return mGroups;
- }
-
- @Override
- @NonNull
- public boolean[] getGroupsDefaultLogcatStatus() {
- return mLogcatStatus;
- }
-
- @Nullable
- @Override
- public String getViewerConfigFile() {
- return mViewerConfigFile;
- }
- }
-
@FunctionalInterface
public interface ViewerConfigFileTracer {
/**
@@ -216,16 +148,16 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
}
@Override
- public void registerClient(@NonNull IProtoLogClient client, @NonNull IRegisterClientArgs args)
+ public void registerClient(@NonNull IProtoLogClient client, @NonNull RegisterClientArgs args)
throws RemoteException {
client.asBinder().linkToDeath(() -> onClientBinderDeath(client), /* flags */ 0);
- final String viewerConfigFile = args.getViewerConfigFile();
+ final String viewerConfigFile = args.viewerConfigFile;
if (viewerConfigFile != null) {
registerViewerConfigFile(client, viewerConfigFile);
}
- registerGroups(client, args.getGroups(), args.getGroupsDefaultLogcatStatus());
+ registerGroups(client, args.groups, args.groupsDefaultLogcatStatus);
}
@Override
diff --git a/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java
index ebb07a04270d..39b01fb59d9e 100644
--- a/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java
@@ -19,7 +19,7 @@ package com.android.internal.protolog;
import android.annotation.NonNull;
import android.os.ServiceManager;
-import com.android.internal.protolog.ProtoLogConfigurationServiceImpl.RegisterClientArgs;
+import com.android.internal.protolog.IProtoLogConfigurationService.RegisterClientArgs;
import com.android.internal.protolog.common.IProtoLogGroup;
public class UnprocessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
diff --git a/core/java/com/android/internal/security/TEST_MAPPING b/core/java/com/android/internal/security/TEST_MAPPING
index 5bd9d2e4512d..be50bebf0831 100644
--- a/core/java/com/android/internal/security/TEST_MAPPING
+++ b/core/java/com/android/internal/security/TEST_MAPPING
@@ -6,10 +6,6 @@
{
"name": "UpdatableSystemFontTest",
"file_patterns": ["VerityUtils\\.java"]
- },
- {
- "name": "CtsApkVerityInstallHostTestCases",
- "file_patterns": ["VerityUtils\\.java"]
}
],
"postsubmit": [
diff --git a/core/java/com/android/internal/security/VerityUtils.java b/core/java/com/android/internal/security/VerityUtils.java
index 37500766a4ac..ac186d0a26b5 100644
--- a/core/java/com/android/internal/security/VerityUtils.java
+++ b/core/java/com/android/internal/security/VerityUtils.java
@@ -56,8 +56,7 @@ public abstract class VerityUtils {
private static final int HASH_SIZE_BYTES = 32;
public static boolean isFsVeritySupported() {
- return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.R
- || SystemProperties.getInt("ro.apk_verity.mode", 0) == 2;
+ return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.R;
}
/** Enables fs-verity for the file without signature. */
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 0ec55f958f38..1f907602cb9b 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -87,10 +87,10 @@ public class LockPatternView extends View {
private static final int CELL_ACTIVATE = 0;
private static final int CELL_DEACTIVATE = 1;
- private final int mDotSize;
- private final int mDotSizeActivated;
+ private int mDotSize;
+ private int mDotSizeActivated;
private final float mDotHitFactor;
- private final int mPathWidth;
+ private int mPathWidth;
private final int mLineFadeOutAnimationDurationMs;
private final int mLineFadeOutAnimationDelayMs;
private final int mFadePatternAnimationDurationMs;
@@ -1341,6 +1341,38 @@ public class LockPatternView extends View {
invalidate();
}
+ /**
+ * Change dot colors
+ */
+ public void setDotColors(int dotColor, int dotActivatedColor) {
+ mDotColor = dotColor;
+ mDotActivatedColor = dotActivatedColor;
+ invalidate();
+ }
+
+ /**
+ * Keeps dot activated until the next dot gets activated.
+ */
+ public void setKeepDotActivated(boolean keepDotActivated) {
+ mKeepDotActivated = keepDotActivated;
+ }
+
+ /**
+ * Set dot sizes in dp
+ */
+ public void setDotSizes(int dotSizeDp, int dotSizeActivatedDp) {
+ mDotSize = dotSizeDp;
+ mDotSizeActivated = dotSizeActivatedDp;
+ }
+
+ /**
+ * Set the stroke width of the pattern line.
+ */
+ public void setPathWidth(int pathWidthDp) {
+ mPathWidth = pathWidthDp;
+ mPathPaint.setStrokeWidth(mPathWidth);
+ }
+
private float getCenterXForColumn(int column) {
return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f;
}
diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java
index 905d4dd547f3..c0fe0d125e44 100644
--- a/core/java/com/android/internal/widget/NotificationProgressBar.java
+++ b/core/java/com/android/internal/widget/NotificationProgressBar.java
@@ -64,6 +64,7 @@ public final class NotificationProgressBar extends ProgressBar implements
NotificationProgressDrawable.BoundsChangeListener {
private static final String TAG = "NotificationProgressBar";
private static final boolean DEBUG = false;
+ private static final float FADED_OPACITY = 0.5f;
private NotificationProgressDrawable mNotificationProgressDrawable;
private final Rect mProgressDrawableBounds = new Rect();
@@ -851,12 +852,12 @@ public final class NotificationProgressBar extends ProgressBar implements
}
/**
- * Get a color with an opacity that's 50% of the input color.
+ * Get a color that's the input color with opacity updated to FADED_OPACITY.
*/
@ColorInt
static int getFadedColor(@ColorInt int color) {
return Color.argb(
- (int) (Color.alpha(color) * 0.5f + 0.5f),
+ (int) (Color.alpha(color) * FADED_OPACITY + 0.5f),
Color.red(color),
Color.green(color),
Color.blue(color));
@@ -1200,7 +1201,7 @@ public final class NotificationProgressBar extends ProgressBar implements
* <p>
* <pre>
* When mFaded is set to true, a combination of the following is done to the segment:
- * 1. The drawing color is mColor with opacity updated to 50%.
+ * 1. The drawing color is mColor with opacity updated to FADED_OPACITY.
* 2. The gap between faded and non-faded segments is:
* - the segment-segment gap, when there is no tracker icon
* - 0, when there is tracker icon
diff --git a/core/java/com/android/internal/widget/remotecompose/OWNERS b/core/java/com/android/internal/widget/remotecompose/OWNERS
index 54facab0c3f4..e163474bccb9 100644
--- a/core/java/com/android/internal/widget/remotecompose/OWNERS
+++ b/core/java/com/android/internal/widget/remotecompose/OWNERS
@@ -5,4 +5,3 @@ sihua@google.com
sunnygoyal@google.com
oscarad@google.com
pinyaoting@google.com
-zakcohen@google.com
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
index dea1caf76a5c..b8503da2c09b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -35,6 +35,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.LoopOper
import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import com.android.internal.widget.remotecompose.core.serialize.Serializable;
@@ -64,7 +65,7 @@ public class CoreDocument implements Serializable {
// We also keep a more fine-grained BUILD number, exposed as
// ID_API_LEVEL = DOCUMENT_API_LEVEL + BUILD
- static final float BUILD = 0.0f;
+ static final float BUILD = 0.2f;
@NonNull ArrayList<Operation> mOperations = new ArrayList<>();
@@ -99,6 +100,8 @@ public class CoreDocument implements Serializable {
private int mLastId = 1; // last component id when inflating the file
+ private IntMap<Object> mDocProperties;
+
/** Returns a version number that is monotonically increasing. */
public static int getDocumentApiLevel() {
return DOCUMENT_API_LEVEL;
@@ -407,10 +410,31 @@ public class CoreDocument implements Serializable {
@Override
public void serialize(MapSerializer serializer) {
- serializer.add("type", "CoreDocument");
- serializer.add("width", mWidth);
- serializer.add("height", mHeight);
- serializer.add("operations", mOperations);
+ serializer
+ .add("type", "CoreDocument")
+ .add("width", mWidth)
+ .add("height", mHeight)
+ .add("operations", mOperations);
+ }
+
+ /**
+ * Set the properties of the document
+ *
+ * @param properties the properties to set
+ */
+ public void setProperties(IntMap<Object> properties) {
+ mDocProperties = properties;
+ }
+
+ /**
+ * @param key the key
+ * @return the value associated with the key
+ */
+ public Object getProperty(short key) {
+ if (mDocProperties == null) {
+ return null;
+ }
+ return mDocProperties.get(key);
}
// ============== Haptic support ==================
@@ -718,6 +742,7 @@ public class CoreDocument implements Serializable {
if (op instanceof Component) {
mComponentMap.put(((Component) op).getComponentId(), (Component) op);
registerVariables(context, ((Component) op).getList());
+ ((Component) op).registerVariables(context);
}
if (op instanceof ComponentValue) {
ComponentValue v = (ComponentValue) op;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
index 9bb8d9f39975..09ec40271f4d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
@@ -35,6 +35,7 @@ import com.android.internal.widget.remotecompose.core.operations.DrawBitmapFontT
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapScaled;
import com.android.internal.widget.remotecompose.core.operations.DrawCircle;
+import com.android.internal.widget.remotecompose.core.operations.DrawContent;
import com.android.internal.widget.remotecompose.core.operations.DrawLine;
import com.android.internal.widget.remotecompose.core.operations.DrawOval;
import com.android.internal.widget.remotecompose.core.operations.DrawPath;
@@ -81,6 +82,7 @@ import com.android.internal.widget.remotecompose.core.operations.Theme;
import com.android.internal.widget.remotecompose.core.operations.TimeAttribute;
import com.android.internal.widget.remotecompose.core.operations.TouchExpression;
import com.android.internal.widget.remotecompose.core.operations.layout.CanvasContent;
+import com.android.internal.widget.remotecompose.core.operations.layout.CanvasOperations;
import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.ComponentStart;
import com.android.internal.widget.remotecompose.core.operations.layout.ContainerEnd;
@@ -105,6 +107,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.BorderModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ClipRectModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentVisibilityOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.DrawContentOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightInModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation;
@@ -172,6 +175,7 @@ public class Operations {
public static final int DATA_PATH = 123;
public static final int DRAW_PATH = 124;
public static final int DRAW_TWEEN_PATH = 125;
+ public static final int DRAW_CONTENT = 139;
public static final int MATRIX_SCALE = 126;
public static final int MATRIX_TRANSLATE = 127;
public static final int MATRIX_SKEW = 128;
@@ -215,6 +219,8 @@ public class Operations {
public static final int ATTRIBUTE_TEXT = 170;
public static final int ATTRIBUTE_IMAGE = 171;
public static final int ATTRIBUTE_TIME = 172;
+ public static final int CANVAS_OPERATIONS = 173;
+ public static final int MODIFIER_DRAW_CONTENT = 174;
///////////////////////////////////////// ======================
@@ -366,6 +372,7 @@ public class Operations {
map.put(MODIFIER_SCROLL, ScrollModifierOperation::read);
map.put(MODIFIER_MARQUEE, MarqueeModifierOperation::read);
map.put(MODIFIER_RIPPLE, RippleModifierOperation::read);
+ map.put(MODIFIER_DRAW_CONTENT, DrawContentOperation::read);
map.put(CONTAINER_END, ContainerEnd::read);
@@ -393,6 +400,7 @@ public class Operations {
map.put(LAYOUT_TEXT, TextLayout::read);
map.put(LAYOUT_STATE, StateLayout::read);
+ map.put(DRAW_CONTENT, DrawContent::read);
map.put(COMPONENT_VALUE, ComponentValue::read);
map.put(DRAW_ARC, DrawArc::read);
@@ -409,6 +417,7 @@ public class Operations {
map.put(PARTICLE_LOOP, ParticlesLoop::read);
map.put(FUNCTION_CALL, FloatFunctionCall::read);
map.put(FUNCTION_DEFINE, FloatFunctionDefine::read);
+ map.put(CANVAS_OPERATIONS, CanvasOperations::read);
map.put(ACCESSIBILITY_SEMANTICS, CoreSemantics::read);
map.put(ATTRIBUTE_IMAGE, ImageAttribute::read);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
index a5b669d6aecf..1b0b9d783dff 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
@@ -207,6 +207,13 @@ public abstract class PaintContext {
public abstract void restorePaint();
/**
+ * Replace the current paint with the PaintBundle
+ *
+ * @param paint
+ */
+ public abstract void replacePaint(PaintBundle paint);
+
+ /**
* draw a round rect
*
* @param left left coordinate of the rectangle
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
index c6ef1d3c457d..e75bd30b381d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
@@ -38,6 +38,7 @@ import com.android.internal.widget.remotecompose.core.operations.DrawBitmapFontT
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapScaled;
import com.android.internal.widget.remotecompose.core.operations.DrawCircle;
+import com.android.internal.widget.remotecompose.core.operations.DrawContent;
import com.android.internal.widget.remotecompose.core.operations.DrawLine;
import com.android.internal.widget.remotecompose.core.operations.DrawOval;
import com.android.internal.widget.remotecompose.core.operations.DrawPath;
@@ -84,6 +85,7 @@ import com.android.internal.widget.remotecompose.core.operations.TimeAttribute;
import com.android.internal.widget.remotecompose.core.operations.TouchExpression;
import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.layout.CanvasContent;
+import com.android.internal.widget.remotecompose.core.operations.layout.CanvasOperations;
import com.android.internal.widget.remotecompose.core.operations.layout.ComponentStart;
import com.android.internal.widget.remotecompose.core.operations.layout.ContainerEnd;
import com.android.internal.widget.remotecompose.core.operations.layout.ImpulseOperation;
@@ -191,6 +193,11 @@ public class RemoteComposeBuffer {
// Supported operations on the buffer
///////////////////////////////////////////////////////////////////////////////////////////////
+ /** Insert a header */
+ public void addHeader(short[] tags, Object[] values) {
+ Header.apply(mBuffer, tags, values);
+ }
+
/**
* Insert a header
*
@@ -219,6 +226,28 @@ public class RemoteComposeBuffer {
* @param width the width of the document in pixels
* @param height the height of the document in pixels
* @param contentDescription content description of the document
+ * @param capabilities bitmask indicating needed capabilities (unused for now)
+ */
+ public void addHeader(
+ int width,
+ int height,
+ @Nullable String contentDescription,
+ float density,
+ long capabilities) {
+ Header.apply(mBuffer, width, height, density, capabilities);
+ int contentDescriptionId = 0;
+ if (contentDescription != null) {
+ contentDescriptionId = addText(contentDescription);
+ RootContentDescription.apply(mBuffer, contentDescriptionId);
+ }
+ }
+
+ /**
+ * Insert a header
+ *
+ * @param width the width of the document in pixels
+ * @param height the height of the document in pixels
+ * @param contentDescription content description of the document
*/
public void header(int width, int height, @Nullable String contentDescription) {
header(width, height, contentDescription, 1f, 0);
@@ -1860,7 +1889,7 @@ public class RemoteComposeBuffer {
}
/** Add a component end tag */
- public void addComponentEnd() {
+ public void addContainerEnd() {
ContainerEnd.apply(mBuffer);
}
@@ -2204,6 +2233,11 @@ public class RemoteComposeBuffer {
LayoutComponentContent.apply(mBuffer, mLastComponentId);
}
+ /** Add a canvas operations start tag */
+ public void addCanvasOperationsStart() {
+ CanvasOperations.apply(mBuffer);
+ }
+
/**
* Add a component width value
*
@@ -2400,4 +2434,9 @@ public class RemoteComposeBuffer {
TimeAttribute.apply(mBuffer, id, timeId, attribute, args);
return Utils.asNan(id);
}
+
+ /** In the context of a component draw modifier, draw the content of the component */
+ public void drawComponentContent() {
+ DrawContent.apply(mBuffer);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index 36e4ec1ff303..622f0c8d12b7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -26,6 +26,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.Componen
import com.android.internal.widget.remotecompose.core.operations.utilities.ArrayAccess;
import com.android.internal.widget.remotecompose.core.operations.utilities.CollectionsAccess;
import com.android.internal.widget.remotecompose.core.operations.utilities.DataMap;
+import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
@@ -392,6 +393,7 @@ public abstract class RemoteContext {
* @param width original width of the document when created
* @param height original height of the document when created
* @param capabilities bitmask of capabilities used in the document (TBD)
+ * @param properties properties of the document (TBD)
*/
public void header(
int majorVersion,
@@ -399,13 +401,15 @@ public abstract class RemoteContext {
int patchVersion,
int width,
int height,
- long capabilities) {
+ long capabilities,
+ IntMap<Object> properties) {
mRemoteComposeState.setWindowWidth(width);
mRemoteComposeState.setWindowHeight(height);
mDocument.setVersion(majorVersion, minorVersion, patchVersion);
mDocument.setWidth(width);
mDocument.setHeight(height);
mDocument.setRequiredCapabilities(capabilities);
+ mDocument.setProperties(properties);
}
/**
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
index a593241888df..d5af7914607a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
@@ -27,6 +27,8 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
@@ -34,7 +36,7 @@ import java.util.List;
* Operation to Colors Color modes mMode = 0 two colors and a tween mMode = 1 color1 is a colorID.
* mMode = 2 color2 is a colorID. mMode = 3 color1 & color2 are ids mMode = 4 H S V mode
*/
-public class ColorExpression extends Operation implements VariableSupport {
+public class ColorExpression extends Operation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.COLOR_EXPRESSIONS;
private static final String CLASS_NAME = "ColorExpression";
public int mId;
@@ -502,4 +504,36 @@ public class ColorExpression extends Operation implements VariableSupport {
public String deepToString(@NonNull String indent) {
return indent + toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("id", mId);
+ switch (mMode) {
+ case COLOR_COLOR_INTERPOLATE:
+ case ID_COLOR_INTERPOLATE:
+ case COLOR_ID_INTERPOLATE:
+ case ID_ID_INTERPOLATE:
+ serializer.add("mode", "TWEEN");
+ serializer.add("startColor", mColor1, mOutColor1);
+ serializer.add("endColor", mColor2, mOutColor2);
+ serializer.add("startColor", mTween, mOutTween);
+ break;
+ case HSV_MODE:
+ serializer.add("mode", "HSV");
+ serializer.add("hue", mHue, mOutHue);
+ serializer.add("sat", mSat, mOutSat);
+ serializer.add("val", mValue, mOutValue);
+ break;
+ case ARGB_MODE:
+ case IDARGB_MODE:
+ serializer.add("mode", "ARGB");
+ serializer.add("a", mArgbAlpha, mOutArgbAlpha);
+ serializer.add("r", mArgbRed, mOutArgbRed);
+ serializer.add("g", mArgbGreen, mOutArgbGreen);
+ serializer.add("b", mArgbBlue, mOutArgbBlue);
+ break;
+ default:
+ serializer.add("mode", "NONE");
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
index 7a72b109b2a8..fb3abdbb0626 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
@@ -28,11 +28,13 @@ import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.ArrayAccess;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.Arrays;
import java.util.List;
-public class DataListFloat extends Operation implements VariableSupport, ArrayAccess {
+public class DataListFloat extends Operation implements VariableSupport, ArrayAccess, Serializable {
private static final int OP_CODE = Operations.FLOAT_LIST;
private static final String CLASS_NAME = "IdListData";
private final int mId;
@@ -145,4 +147,9 @@ public class DataListFloat extends Operation implements VariableSupport, ArrayAc
public int getLength() {
return mValues.length;
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("id", mId).add("values", List.of(mValues));
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
index 7e29620ec104..58fd74fdcf3e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java
@@ -29,11 +29,13 @@ import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.ArrayAccess;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.Arrays;
import java.util.List;
-public class DataListIds extends Operation implements VariableSupport, ArrayAccess {
+public class DataListIds extends Operation implements VariableSupport, ArrayAccess, Serializable {
private static final int OP_CODE = Operations.ID_LIST;
private static final String CLASS_NAME = "IdListData";
private final int mId;
@@ -147,4 +149,9 @@ public class DataListIds extends Operation implements VariableSupport, ArrayAcce
public int getIntValue(int index) {
return 0;
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("id", mId).add("ids", List.of(mIds));
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
index 6df4b91cc405..5dbaf29b8cc0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
@@ -121,6 +121,6 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor
}
protected MapSerializer serialize(MapSerializer serializer, String v1Name, String v2Name) {
- return serializer.add(v1Name, mV1, mValue1).add(v2Name, mV2, mValue2);
+ return serializer.add(v1Name, mValue1, mV1).add(v2Name, mValue2, mV2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
index 16ead454d84f..238f10e794d0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
@@ -126,8 +126,8 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor
protected MapSerializer serialize(
MapSerializer serializer, String v1Name, String v2Name, String v3Name) {
return serializer
- .add(v1Name, mV1, mValue1)
- .add(v2Name, mV2, mValue2)
- .add(v3Name, mV3, mValue3);
+ .add(v1Name, mValue1, mV1)
+ .add(v2Name, mValue2, mV2)
+ .add(v3Name, mValue3, mV3);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
index 0733b833be11..ca34e01f1725 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
@@ -158,9 +158,9 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor
protected MapSerializer serialize(
MapSerializer serializer, String x1Name, String y1Name, String x2Name, String y2Name) {
return serializer
- .add(x1Name, mX1, mX1Value)
- .add(y1Name, mY1, mY1Value)
- .add(x2Name, mX2, mX2Value)
- .add(y2Name, mY2, mY2Value);
+ .add(x1Name, mX1Value, mX1)
+ .add(y1Name, mY1Value, mY1)
+ .add(x2Name, mX2Value, mX2)
+ .add(y2Name, mY2Value, mY2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
index 75b87c04e810..ca0584d0ee73 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
@@ -173,11 +173,11 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor
String v5Name,
String v6Name) {
return serializer
- .add(v1Name, mV1, mValue1)
- .add(v2Name, mV2, mValue2)
- .add(v3Name, mV3, mValue3)
- .add(v4Name, mV4, mValue4)
- .add(v5Name, mV5, mValue5)
- .add(v6Name, mV6, mValue6);
+ .add(v1Name, mValue1, mV1)
+ .add(v2Name, mValue2, mV2)
+ .add(v3Name, mValue3, mV3)
+ .add(v4Name, mValue4, mV4)
+ .add(v5Name, mValue5, mV5)
+ .add(v6Name, mValue6, mV6);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java
new file mode 100644
index 000000000000..e2e22acbeb8f
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawContent.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
+
+import java.util.List;
+
+/** The DrawContent command */
+public class DrawContent extends PaintOperation implements Serializable {
+ private static final int OP_CODE = Operations.DRAW_CONTENT;
+ private static final String CLASS_NAME = "DrawContent";
+ private @Nullable LayoutComponent mComponent;
+
+ @Override
+ public void write(@NonNull WireBuffer buffer) {
+ apply(buffer);
+ }
+
+ /**
+ * Set the component to be painted
+ *
+ * @param component
+ */
+ public void setComponent(LayoutComponent component) {
+ mComponent = component;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "DrawContent;";
+ }
+
+ /**
+ * Read this operation and add it to the list of operations
+ *
+ * @param buffer the buffer to read
+ * @param operations the list of operations that will be added to
+ */
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+ DrawContent op = new DrawContent();
+ operations.add(op);
+ }
+
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
+ public static String name() {
+ return CLASS_NAME;
+ }
+
+ /**
+ * The OP_CODE for this command
+ *
+ * @return the opcode
+ */
+ public static int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * add a draw content operation to the buffer
+ *
+ * @param buffer the buffer to add to
+ */
+ public static void apply(@NonNull WireBuffer buffer) {
+ buffer.start(Operations.DRAW_CONTENT);
+ }
+
+ /**
+ * Populate the documentation with a description of this operation
+ *
+ * @param doc to append the description to.
+ */
+ public static void documentation(@NonNull DocumentationBuilder doc) {
+ doc.operation("Layout Operations", OP_CODE, CLASS_NAME)
+ .description("Draw the component content");
+ }
+
+ @Override
+ public void paint(@NonNull PaintContext context) {
+ if (mComponent != null) {
+ mComponent.drawContent(context);
+ }
+ }
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
index 5d0c43723ea1..92469d1834ba 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
@@ -26,11 +26,13 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Draw Text in Anchored to a point */
-public class DrawTextAnchored extends PaintOperation implements VariableSupport {
+public class DrawTextAnchored extends PaintOperation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.DRAW_TEXT_ANCHOR;
private static final String CLASS_NAME = "DrawTextAnchored";
int mTextID;
@@ -238,4 +240,16 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport
float y = Float.isNaN(mOutPanY) ? mOutY : mOutY + getVerticalOffset();
context.drawTextRun(mTextID, 0, -1, 0, 1, x, y, (mFlags & ANCHOR_TEXT_RTL) == 1);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("textId", mTextID)
+ .add("x", mX, mOutX)
+ .add("y", mY, mOutY)
+ .add("panX", mPanX, mOutPanX)
+ .add("panY", mPanY, mOutPanY)
+ .add("flags", mFlags);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
index 3ab4a87c614c..1f7910ede4b5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
@@ -26,11 +26,13 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Draw text along a path. */
-public class DrawTextOnPath extends PaintOperation implements VariableSupport {
+public class DrawTextOnPath extends PaintOperation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.DRAW_TEXT_ON_PATH;
private static final String CLASS_NAME = "DrawTextOnPath";
int mPathId;
@@ -153,4 +155,14 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport {
public void paint(@NonNull PaintContext context) {
context.drawTextOnPath(mTextId, mPathId, mOutHOffset, mOutVOffset);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("pathId", mPathId)
+ .add("textId", mTextId)
+ .add("vOffset", mVOffset, mOutVOffset)
+ .add("hOffset", mHOffset, mOutHOffset);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
index e04e691c312c..7f3c3ed6bcff 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
@@ -25,30 +25,32 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
-/** Operation to deal with Text data */
-public class FloatConstant extends Operation {
+/** Used to represent a float */
+public class FloatConstant extends Operation implements Serializable {
private static final int OP_CODE = Operations.DATA_FLOAT;
private static final String CLASS_NAME = "FloatConstant";
- public int mTextId;
+ public int mId;
public float mValue;
- public FloatConstant(int textId, float value) {
- this.mTextId = textId;
+ public FloatConstant(int id, float value) {
+ this.mId = id;
this.mValue = value;
}
@Override
public void write(@NonNull WireBuffer buffer) {
- apply(buffer, mTextId, mValue);
+ apply(buffer, mId, mValue);
}
@NonNull
@Override
public String toString() {
- return "FloatConstant[" + mTextId + "] = " + mValue;
+ return "FloatConstant[" + mId + "] = " + mValue;
}
/**
@@ -90,10 +92,10 @@ public class FloatConstant extends Operation {
* @param operations the list of operations that will be added to
*/
public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
- int textId = buffer.readInt();
+ int id = buffer.readInt();
float value = buffer.readFloat();
- operations.add(new FloatConstant(textId, value));
+ operations.add(new FloatConstant(id, value));
}
/**
@@ -110,7 +112,7 @@ public class FloatConstant extends Operation {
@Override
public void apply(@NonNull RemoteContext context) {
- context.loadFloat(mTextId, mValue);
+ context.loadFloat(mId, mValue);
}
@NonNull
@@ -118,4 +120,9 @@ public class FloatConstant extends Operation {
public String deepToString(@NonNull String indent) {
return indent + toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("id", mId).add("value", mValue);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
index e09745aa8546..c1fa898ec619 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
@@ -34,6 +34,9 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.Anima
import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap;
import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
import com.android.internal.widget.remotecompose.core.operations.utilities.easing.SpringStopEngine;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
+import com.android.internal.widget.remotecompose.core.serialize.SerializeTags;
import java.util.List;
@@ -42,7 +45,7 @@ import java.util.List;
* like injecting the width of the component int draw rect As well as supporting generalized
* animation floats. The floats represent a RPN style calculator
*/
-public class FloatExpression extends Operation implements VariableSupport {
+public class FloatExpression extends Operation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.ANIMATED_FLOAT;
private static final String CLASS_NAME = "FloatExpression";
public int mId;
@@ -336,4 +339,14 @@ public class FloatExpression extends Operation implements VariableSupport {
public String deepToString(@NonNull String indent) {
return indent + toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addTags(SerializeTags.EXPRESSION)
+ .add("type", CLASS_NAME)
+ .add("id", mId)
+ .addFloatExpressionSrc("srcValues", mSrcValue)
+ .add("animation", mFloatAnimation);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
index 98c2745380d7..3d6316b67e8f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
@@ -30,7 +30,11 @@ import com.android.internal.widget.remotecompose.core.RemoteComposeOperation;
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.List;
/**
@@ -42,16 +46,75 @@ import java.util.List;
public class Header extends Operation implements RemoteComposeOperation {
private static final int OP_CODE = Operations.HEADER;
private static final String CLASS_NAME = "Header";
+ private static final int MAGIC_NUMBER = 0x048C0000; // to uniquly identify the protocol
int mMajorVersion;
int mMinorVersion;
int mPatchVersion;
- int mWidth;
- int mHeight;
+ int mWidth = 256;
+ int mHeight = 256;
- float mDensity;
- long mCapabilities;
+ float mDensity = 3;
+ long mCapabilities = 0;
+ private IntMap<Object> mProperties;
+
+ /**
+ * Get a property on the header
+ *
+ * @param property the property to get
+ * @return the value of the property
+ */
+ public Object get(short property) {
+ return mProperties.get(property);
+ }
+
+ /** the width of the document */
+ public static final short DOC_WIDTH = 5;
+
+ /** The height of the document */
+ public static final short DOC_HEIGHT = 6;
+
+ /** The density at generation */
+ public static final short DOC_DENSITY_AT_GENERATION = 7;
+
+ /** The desired FPS for the document */
+ public static final short DOC_DESIRED_FPS = 8;
+
+ /** The description of the contents of the document */
+ public static final short DOC_CONTENT_DESCRIPTION = 9;
+
+ /** The source of the document */
+ public static final short DOC_SOURCE = 11;
+
+ /** The object is an integer */
+ private static final short DATA_TYPE_INT = 0;
+
+ /** The object is an float */
+ private static final short DATA_TYPE_FLOAT = 1;
+
+ /** The object is an LONG */
+ private static final short DATA_TYPE_LONG = 2;
+
+ /** The object is an UTF-8 encoded string */
+ private static final short DATA_TYPE_STRING = 3;
+
+ private static final short[] KEYS = {
+ DOC_WIDTH,
+ DOC_HEIGHT,
+ DOC_DENSITY_AT_GENERATION,
+ DOC_DESIRED_FPS,
+ DOC_CONTENT_DESCRIPTION,
+ DOC_SOURCE
+ };
+ private static final String[] KEY_NAMES = {
+ "DOC_WIDTH",
+ "DOC_HEIGHT",
+ "DOC_DENSITY_AT_GENERATION",
+ "DOC_DESIRED_FPS",
+ "DOC_CONTENT_DESCRIPTION",
+ "DOC_SOURCE"
+ };
/**
* It encodes the version of the document (following semantic versioning) as well as the
@@ -82,6 +145,60 @@ public class Header extends Operation implements RemoteComposeOperation {
this.mCapabilities = capabilities;
}
+ /**
+ * @param majorVersion the major version of the RemoteCompose document API
+ * @param minorVersion the minor version of the RemoteCompose document API
+ * @param patchVersion the patch version of the RemoteCompose document API
+ * @param properties the properties of the document
+ */
+ public Header(int majorVersion, int minorVersion, int patchVersion, IntMap<Object> properties) {
+ this.mMajorVersion = majorVersion;
+ this.mMinorVersion = minorVersion;
+ this.mPatchVersion = patchVersion;
+ if (properties != null) {
+ this.mProperties = properties;
+ this.mWidth = getInt(DOC_WIDTH, 256);
+ this.mHeight = getInt(DOC_HEIGHT, 256);
+ this.mDensity = getFloat(DOC_DENSITY_AT_GENERATION, 0);
+ }
+ }
+
+ private int getInt(int key, int defaultValue) {
+ Integer value = (Integer) mProperties.get(key);
+ if (value != null) {
+ return value;
+ } else {
+ return defaultValue;
+ }
+ }
+
+ private long getLong(int key, long defaultValue) {
+ Long value = (Long) mProperties.get(key);
+ if (value != null) {
+ return value;
+ } else {
+ return defaultValue;
+ }
+ }
+
+ private float getFloat(int key, float defaultValue) {
+ Float value = (Float) mProperties.get(key);
+ if (value != null) {
+ return value;
+ } else {
+ return defaultValue;
+ }
+ }
+
+ private String getString(int key, String defaultValue) {
+ String value = (String) mProperties.get(key);
+ if (value != null) {
+ return value;
+ } else {
+ return defaultValue;
+ }
+ }
+
@Override
public void write(@NonNull WireBuffer buffer) {
apply(buffer, mWidth, mHeight, mDensity, mCapabilities);
@@ -90,6 +207,16 @@ public class Header extends Operation implements RemoteComposeOperation {
@NonNull
@Override
public String toString() {
+ String prop = "";
+ if (mProperties != null) {
+ for (int i = 0; i < KEYS.length; i++) {
+ Object p = mProperties.get(KEYS[i]);
+ if (p != null) {
+ prop += "\n " + KEY_NAMES[i] + " " + p.toString();
+ }
+ }
+ return "HEADER v" + mMajorVersion + "." + mMinorVersion + "." + mPatchVersion + prop;
+ }
return "HEADER v"
+ mMajorVersion
+ "."
@@ -102,12 +229,20 @@ public class Header extends Operation implements RemoteComposeOperation {
+ mHeight
+ " ["
+ mCapabilities
- + "]";
+ + "]"
+ + prop;
}
@Override
public void apply(@NonNull RemoteContext context) {
- context.header(mMajorVersion, mMinorVersion, mPatchVersion, mWidth, mHeight, mCapabilities);
+ context.header(
+ mMajorVersion,
+ mMinorVersion,
+ mPatchVersion,
+ mWidth,
+ mHeight,
+ mCapabilities,
+ mProperties);
}
@NonNull
@@ -157,22 +292,44 @@ public class Header extends Operation implements RemoteComposeOperation {
}
/**
- * Read this operation and add it to the list of operations
+ * Apply the header to the wire buffer
*
- * @param buffer the buffer to read
- * @param operations the list of operations that will be added to
+ * @param buffer
*/
- public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
- int majorVersion = buffer.readInt();
- int minorVersion = buffer.readInt();
- int patchVersion = buffer.readInt();
- int width = buffer.readInt();
- int height = buffer.readInt();
- // float density = buffer.readFloat();
- float density = 1f;
- long capabilities = buffer.readLong();
- Header header =
- new Header(
+ public static void apply(@NonNull WireBuffer buffer, short[] type, Object[] value) {
+ buffer.start(OP_CODE);
+ buffer.writeInt(MAJOR_VERSION | MAGIC_NUMBER); // major version number of the protocol
+ buffer.writeInt(MINOR_VERSION); // minor version number of the protocol
+ buffer.writeInt(PATCH_VERSION); // patch version number of the protocol
+ buffer.writeInt(type.length);
+ writeMap(buffer, type, value);
+ }
+
+ /**
+ * @param is the stream to read from
+ * @return the header
+ * @throws IOException if there is an error reading the header
+ */
+ public static Header readDirect(InputStream is) throws IOException {
+ DataInputStream stream = new DataInputStream(is);
+ try {
+
+ int type = stream.readByte();
+
+ if (type != OP_CODE) {
+ throw new IOException("Invalid header " + type + " != " + OP_CODE);
+ }
+ int majorVersion = stream.readInt();
+ int minorVersion = stream.readInt();
+ int patchVersion = stream.readInt();
+
+ if (majorVersion < 0x10000) {
+ int width = stream.readInt();
+ int height = stream.readInt();
+ // float density = is.read();
+ float density = 1f;
+ long capabilities = stream.readLong();
+ return new Header(
majorVersion,
minorVersion,
patchVersion,
@@ -180,7 +337,173 @@ public class Header extends Operation implements RemoteComposeOperation {
height,
density,
capabilities);
- operations.add(header);
+ }
+
+ if ((majorVersion & 0xFFFF0000) != MAGIC_NUMBER) {
+ throw new IOException(
+ "Invalid header MAGIC_NUMBER "
+ + (majorVersion & 0xFFFF0000)
+ + " != "
+ + MAGIC_NUMBER);
+ }
+ majorVersion &= 0xFFFF;
+ int len = stream.readInt();
+ short[] types = new short[len];
+ Object[] values = new Object[len];
+ readMap(stream, types, values);
+ IntMap<Object> map = new IntMap<>();
+ for (int i = 0; i < len; i++) {
+ map.put(types[i], values[i]);
+ }
+ return new Header(majorVersion, minorVersion, patchVersion, map);
+
+ } finally {
+ stream.close();
+ }
+ }
+
+ /**
+ * Read this operation and add it to the list of operations
+ *
+ * @param stream the buffer to read
+ * @param types the list of types that will be populated
+ * @param values the list of values that will be populated
+ */
+ private static void readMap(DataInputStream stream, short[] types, Object[] values)
+ throws IOException {
+ for (int i = 0; i < types.length; i++) {
+ short tag = (short) stream.readShort();
+ int itemLen = stream.readShort();
+ int dataType = tag >> 10;
+ types[i] = (short) (tag & 0x3F);
+ Object value;
+ switch (dataType) {
+ case DATA_TYPE_INT:
+ values[i] = stream.readInt();
+ break;
+ case DATA_TYPE_FLOAT:
+ values[i] = stream.readFloat();
+ break;
+ case DATA_TYPE_LONG:
+ values[i] = stream.readLong();
+ break;
+ case DATA_TYPE_STRING:
+ int slen = stream.readInt();
+ byte[] data = new byte[slen];
+ stream.readFully(data);
+ values[i] = new String(data);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Read this operation and add it to the list of operations
+ *
+ * @param buffer the buffer to read
+ * @param operations the list of operations that will be added to
+ */
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+ int majorVersion = buffer.readInt();
+ int minorVersion = buffer.readInt();
+ int patchVersion = buffer.readInt();
+ if (majorVersion < 0x10000) {
+ int width = buffer.readInt();
+ int height = buffer.readInt();
+ // float density = buffer.readFloat();
+ float density = 1f;
+ long capabilities = buffer.readLong();
+ Header header =
+ new Header(
+ majorVersion,
+ minorVersion,
+ patchVersion,
+ width,
+ height,
+ density,
+ capabilities);
+ operations.add(header);
+ } else {
+ majorVersion &= 0xFFFF;
+ int length = buffer.readInt();
+ short[] types = new short[length];
+ Object[] values = new Object[length];
+ readMap(buffer, types, values);
+ IntMap<Object> map = new IntMap<>();
+ for (int i = 0; i < length; i++) {
+ map.put(types[i], values[i]);
+ }
+ Header header = new Header(majorVersion, minorVersion, patchVersion, map);
+ operations.add(header);
+ }
+ }
+
+ /**
+ * Read this operation and add it to the list of operations
+ *
+ * @param buffer the buffer to read
+ * @param types the list of types that will be populated
+ * @param values the list of values that will be populated
+ */
+ private static void readMap(@NonNull WireBuffer buffer, short[] types, Object[] values) {
+ for (int i = 0; i < types.length; i++) {
+ short tag = (short) buffer.readShort();
+ int itemLen = buffer.readShort();
+ int dataType = tag >> 10;
+ types[i] = (short) (tag & 0x3F);
+ Object value;
+ switch (dataType) {
+ case DATA_TYPE_INT:
+ values[i] = buffer.readInt();
+ break;
+ case DATA_TYPE_FLOAT:
+ values[i] = buffer.readFloat();
+ break;
+ case DATA_TYPE_LONG:
+ values[i] = buffer.readLong();
+ break;
+ case DATA_TYPE_STRING:
+ values[i] = buffer.readUTF8();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Write the map of values to the buffer
+ *
+ * @param buffer the buffer to read
+ * @param types the list of types that will be written
+ * @param values the list of values that will be written
+ */
+ private static void writeMap(@NonNull WireBuffer buffer, short[] types, Object[] values) {
+ for (int i = 0; i < types.length; i++) {
+ short tag = types[i];
+ if (values[i] instanceof String) {
+ tag = (short) (tag | (DATA_TYPE_STRING << 10));
+ buffer.writeShort(tag);
+ String str = (String) values[i];
+ byte[] data = str.getBytes();
+ buffer.writeShort((data.length + 4));
+ buffer.writeBuffer(data);
+ } else if (values[i] instanceof Integer) {
+ tag = (short) (tag | (DATA_TYPE_INT << 10));
+ buffer.writeShort(tag);
+ buffer.writeShort(4);
+ buffer.writeInt((Integer) values[i]);
+ } else if (values[i] instanceof Float) {
+ tag = (short) (tag | (DATA_TYPE_FLOAT << 10));
+ buffer.writeShort(tag);
+ buffer.writeShort(4);
+
+ buffer.writeFloat((float) values[i]);
+ } else if (values[i] instanceof Long) {
+ tag = (short) (tag | (DATA_TYPE_LONG << 10));
+ buffer.writeShort(tag);
+ buffer.writeShort(8);
+ buffer.writeLong((Long) values[i]);
+ }
+ }
}
/**
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
index f04f30dc62fb..2a5260c0c9b1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
@@ -29,6 +29,9 @@ import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.IntegerExpressionEvaluator;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
+import com.android.internal.widget.remotecompose.core.serialize.SerializeTags;
import java.util.Arrays;
import java.util.List;
@@ -38,7 +41,7 @@ import java.util.List;
* like injecting the width of the component int draw rect As well as supporting generalized
* animation floats. The floats represent a RPN style calculator
*/
-public class IntegerExpression extends Operation implements VariableSupport {
+public class IntegerExpression extends Operation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.INTEGER_EXPRESSION;
private static final String CLASS_NAME = "IntegerExpression";
public int mId;
@@ -225,4 +228,14 @@ public class IntegerExpression extends Operation implements VariableSupport {
public static boolean isId(int mask, int i, int value) {
return ((1 << i) & mask) != 0 && value < IntegerExpressionEvaluator.OFFSET;
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addTags(SerializeTags.EXPRESSION)
+ .add("type", CLASS_NAME)
+ .add("id", mId)
+ .add("mask", mId)
+ .addIntExpressionSrc("srcValues", mSrcValue, mMask);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
index dde632e0c346..96628fd51225 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
@@ -26,11 +26,13 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Operation to deal with Text data */
-public class NamedVariable extends Operation {
+public class NamedVariable extends Operation implements Serializable {
private static final int OP_CODE = Operations.NAMED_VARIABLE;
private static final String CLASS_NAME = "NamedVariable";
public final int mVarId;
@@ -135,4 +137,28 @@ public class NamedVariable extends Operation {
public String deepToString(@NonNull String indent) {
return indent + toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("varId", mVarId)
+ .add("varName", mVarName)
+ .add("varType", typeToString());
+ }
+
+ private String typeToString() {
+ switch (mVarType) {
+ case COLOR_TYPE:
+ return "COLOR_TYPE";
+ case FLOAT_TYPE:
+ return "FLOAT_TYPE";
+ case STRING_TYPE:
+ return "STRING_TYPE";
+ case IMAGE_TYPE:
+ return "IMAGE_TYPE";
+ default:
+ return "INVALID_TYPE";
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
index f756b76b86c3..8389aa707ee6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
@@ -29,11 +29,13 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Paint data operation */
-public class PaintData extends PaintOperation implements VariableSupport {
+public class PaintData extends PaintOperation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.PAINT_VALUES;
private static final String CLASS_NAME = "PaintData";
@NonNull public PaintBundle mPaintData = new PaintBundle();
@@ -126,4 +128,9 @@ public class PaintData extends PaintOperation implements VariableSupport {
public void paint(@NonNull PaintContext context) {
context.applyPaint(mPaintData);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("paintBundle", mPaintData);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
index e7cce03f0c4b..8f353ce4a26b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
@@ -30,11 +30,13 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.Arrays;
import java.util.List;
-public class PathAppend extends PaintOperation implements VariableSupport {
+public class PathAppend extends PaintOperation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.PATH_ADD;
private static final String CLASS_NAME = "PathAppend";
int mInstanceId;
@@ -253,4 +255,12 @@ public class PathAppend extends PaintOperation implements VariableSupport {
}
return str.toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("id", mInstanceId)
+ .add("path", pathString(mFloatPath));
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
index 1f76639b1b1f..7aa3390b53ee 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
@@ -29,11 +29,13 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.Arrays;
import java.util.List;
-public class PathCreate extends PaintOperation implements VariableSupport {
+public class PathCreate extends PaintOperation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.PATH_CREATE;
private static final String CLASS_NAME = "PathCreate";
int mInstanceId;
@@ -237,4 +239,12 @@ public class PathCreate extends PaintOperation implements VariableSupport {
public void apply(@NonNull RemoteContext context) {
context.loadPathData(mInstanceId, mOutputPath);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("id", mInstanceId)
+ .add("path", pathString(mFloatPath));
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
index 65adfeabefa6..c5add57d4dd0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
@@ -29,11 +29,13 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Operation to deal with Path data */
-public class PathTween extends PaintOperation implements VariableSupport {
+public class PathTween extends PaintOperation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.PATH_TWEEN;
private static final String CLASS_NAME = "PathTween";
public int mOutId;
@@ -155,4 +157,14 @@ public class PathTween extends PaintOperation implements VariableSupport {
public void paint(PaintContext context) {
context.tweenPath(mOutId, mPathId1, mPathId2, mTweenOut);
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("outId", mOutId)
+ .add("pathId1", mPathId1)
+ .add("pathId2", mPathId2)
+ .add("tween", mTween, mTweenOut);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
index c1ddf63264fa..a6a8a810d2ad 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
@@ -25,12 +25,14 @@ import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Describe a content description for the document */
public class RootContentDescription extends Operation
- implements RemoteComposeOperation, AccessibleComponent {
+ implements RemoteComposeOperation, AccessibleComponent, Serializable {
private static final int OP_CODE = Operations.ROOT_CONTENT_DESCRIPTION;
private static final String CLASS_NAME = "RootContentDescription";
int mContentDescription;
@@ -128,4 +130,9 @@ public class RootContentDescription extends Operation
.description("Content description of root")
.field(DocumentedOperation.INT, "id", "id of Int");
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("contentDescriptionId", mContentDescription);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
index 46a32905b96c..5f6162b68e9e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
@@ -32,6 +32,8 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.Arrays;
import java.util.HashMap;
@@ -41,7 +43,7 @@ import java.util.List;
* Operation to deal with bitmap data On getting an Image during a draw call the bitmap is
* compressed and saved in playback the image is decompressed
*/
-public class ShaderData extends Operation implements VariableSupport {
+public class ShaderData extends Operation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.DATA_SHADER;
private static final String CLASS_NAME = "ShaderData";
int mShaderTextId; // the actual text of a shader
@@ -384,4 +386,15 @@ public class ShaderData extends Operation implements VariableSupport {
public void enable(boolean shaderValid) {
mShaderValid = shaderValid;
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("shaderTextId", mShaderTextId)
+ .add("shaderID", mShaderID)
+ .add("uniformRawFloatMap", mUniformRawFloatMap)
+ .add("uniformFloatMap", mUniformFloatMap)
+ .add("uniformBitmapMap", mUniformBitmapMap);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java
index 45cced3f8b45..3e72995de9db 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextAttribute.java
@@ -27,11 +27,13 @@ import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Operation to Measure Text data */
-public class TextAttribute extends PaintOperation {
+public class TextAttribute extends PaintOperation implements Serializable {
private static final int OP_CODE = Operations.ATTRIBUTE_TEXT;
private static final String CLASS_NAME = "TextMeasure";
public int mId;
@@ -167,4 +169,34 @@ public class TextAttribute extends PaintOperation {
break;
}
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("id", mId)
+ .add("textId", mTextId)
+ .add("measureType", typeToString());
+ }
+
+ private String typeToString() {
+ switch (mType) {
+ case MEASURE_WIDTH:
+ return "MEASURE_WIDTH";
+ case MEASURE_HEIGHT:
+ return "MEASURE_HEIGHT";
+ case MEASURE_LEFT:
+ return "MEASURE_LEFT";
+ case MEASURE_RIGHT:
+ return "MEASURE_RIGHT";
+ case MEASURE_TOP:
+ return "MEASURE_TOP";
+ case MEASURE_BOTTOM:
+ return "MEASURE_BOTTOM";
+ case TEXT_LENGTH:
+ return "TEXT_LENGTH";
+ default:
+ return "INVALID_TYPE";
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
index 5788d8f4da64..419e6d074479 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
@@ -27,11 +27,13 @@ import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Operation to deal with Text data */
-public class TextData extends Operation implements SerializableToString {
+public class TextData extends Operation implements SerializableToString, Serializable {
private static final int OP_CODE = Operations.DATA_TEXT;
private static final String CLASS_NAME = "TextData";
public final int mTextId;
@@ -131,4 +133,9 @@ public class TextData extends Operation implements SerializableToString {
private String getSerializedName() {
return "DATA_TEXT";
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("textId", mTextId).add("text", mText);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
index cc0ff025f09b..6b2f49be76f0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
@@ -28,6 +28,8 @@ import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringUtils;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
@@ -36,7 +38,7 @@ import java.util.List;
* [command][textID][before,after][flags] before and after define number of digits before and after
* the decimal point
*/
-public class TextFromFloat extends Operation implements VariableSupport {
+public class TextFromFloat extends Operation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.TEXT_FROM_FLOAT;
private static final String CLASS_NAME = "TextFromFloat";
public int mTextId;
@@ -209,4 +211,15 @@ public class TextFromFloat extends Operation implements VariableSupport {
public String deepToString(@NonNull String indent) {
return indent + toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("textId", mTextId)
+ .add("value", mValue, mOutValue)
+ .add("digitsBefore", mDigitsBefore)
+ .add("digitsAfter", mDigitsAfter)
+ .add("flags", mFlags);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
index dceb8b67ec3a..e8865c26db12 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
@@ -26,6 +26,8 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
@@ -34,7 +36,7 @@ import java.util.List;
* [command][textID][before,after][flags] before and after define number of digits before and after
* the decimal point
*/
-public class TextLookup extends Operation implements VariableSupport {
+public class TextLookup extends Operation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.TEXT_LOOKUP;
private static final String CLASS_NAME = "TextFromFloat";
public int mTextId;
@@ -150,4 +152,13 @@ public class TextLookup extends Operation implements VariableSupport {
public String deepToString(@NonNull String indent) {
return indent + toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("textId", mTextId)
+ .add("dataSetId", mDataSetId)
+ .add("indexId", mIndex, mOutIndex);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
index 823b70656c86..de2025569d46 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
@@ -26,11 +26,13 @@ import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Operation convert int index of a list to text */
-public class TextLookupInt extends Operation implements VariableSupport {
+public class TextLookupInt extends Operation implements VariableSupport, Serializable {
private static final int OP_CODE = Operations.TEXT_LOOKUP_INT;
private static final String CLASS_NAME = "TextFromINT";
public int mTextId;
@@ -143,4 +145,13 @@ public class TextLookupInt extends Operation implements VariableSupport {
public String deepToString(@NonNull String indent) {
return indent + toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("textId", mTextId)
+ .add("dataSetId", mDataSetId)
+ .add("indexId", mIndex, mOutIndex);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
index d69561566b56..262916dd9d0c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
@@ -25,11 +25,13 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Operation to deal with Text data */
-public class TextMerge extends Operation {
+public class TextMerge extends Operation implements Serializable {
private static final int OP_CODE = Operations.TEXT_MERGE;
private static final String CLASS_NAME = "TextMerge";
public int mTextId;
@@ -126,4 +128,13 @@ public class TextMerge extends Operation {
public String deepToString(@NonNull String indent) {
return indent + toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("id", mTextId)
+ .add("leftId", mSrcId1)
+ .add("rightId", mSrcId2);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
index 997628140c46..2591a4c39778 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
@@ -35,6 +35,8 @@ import com.android.internal.widget.remotecompose.core.operations.layout.RootLayo
import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression;
import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap;
import com.android.internal.widget.remotecompose.core.operations.utilities.touch.VelocityEasing;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.Arrays;
import java.util.List;
@@ -44,7 +46,8 @@ import java.util.List;
* touch behaviours. Including animating to Notched, positions. and tweaking the dynamics of the
* animation.
*/
-public class TouchExpression extends Operation implements VariableSupport, TouchListener {
+public class TouchExpression extends Operation
+ implements VariableSupport, TouchListener, Serializable {
private static final int OP_CODE = Operations.TOUCH_EXPRESSION;
private static final String CLASS_NAME = "TouchExpression";
private float mDefValue;
@@ -709,4 +712,16 @@ public class TouchExpression extends Operation implements VariableSupport, Touch
public String deepToString(@NonNull String indent) {
return indent + toString();
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("id", mId)
+ .add("mDefValue", mDefValue, mOutDefValue)
+ .add("min", mMin, mOutMin)
+ .add("max", mMax, mOutMax)
+ .add("mode", mMode)
+ .addFloatExpressionSrc("srcExp", mSrcExp);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java
new file mode 100644
index 000000000000..3e7f1d304315
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasOperations.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.layout;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.ComponentValue;
+import com.android.internal.widget.remotecompose.core.operations.DrawContent;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Represents a list of canvas operations. */
+public class CanvasOperations extends PaintOperation
+ implements VariableSupport, Container, Serializable {
+ private static final int OP_CODE = Operations.CANVAS_OPERATIONS;
+ private static final String CLASS_NAME = "CanvasOperations";
+
+ @NonNull public ArrayList<Operation> mList = new ArrayList<>();
+ @Nullable LayoutComponent mComponent;
+
+ /** The constructor */
+ public CanvasOperations() {}
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ for (Operation operation : mList) {
+ if (operation instanceof VariableSupport) {
+ VariableSupport variableSupport = (VariableSupport) operation;
+ variableSupport.registerListening(context);
+ }
+ if (operation instanceof ComponentValue) {
+ ComponentValue v = (ComponentValue) operation;
+ mComponent.addComponentValue(v);
+ }
+ }
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ for (Operation operation : mList) {
+ if (operation instanceof VariableSupport) {
+ VariableSupport variableSupport = (VariableSupport) operation;
+ variableSupport.updateVariables(context);
+ }
+ }
+ }
+
+ /**
+ * The returns a list to be filled
+ *
+ * @return list to be filled
+ */
+ @NonNull
+ public ArrayList<Operation> getList() {
+ return mList;
+ }
+
+ @Override
+ public void write(@NonNull WireBuffer buffer) {
+ apply(buffer);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder(CLASS_NAME + "\n");
+ for (Operation operation : mList) {
+ builder.append(" ");
+ builder.append(operation);
+ builder.append("\n");
+ }
+ return builder.toString();
+ }
+
+ @NonNull
+ @Override
+ public String deepToString(@NonNull String indent) {
+ return (indent != null ? indent : "") + toString();
+ }
+
+ @Override
+ public void paint(@NonNull PaintContext context) {
+ RemoteContext remoteContext = context.getContext();
+ for (Operation op : mList) {
+ if (op instanceof VariableSupport && op.isDirty()) {
+ ((VariableSupport) op).updateVariables(context.getContext());
+ }
+ remoteContext.incrementOpCount();
+ op.apply(context.getContext());
+ }
+ }
+
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
+ public static String name() {
+ return "Loop";
+ }
+
+ /**
+ * Apply this operation to the buffer
+ *
+ * @param buffer
+ */
+ public static void apply(@NonNull WireBuffer buffer) {
+ buffer.start(OP_CODE);
+ }
+
+ /**
+ * Read this operation and add it to the list of operations
+ *
+ * @param buffer the buffer to read
+ * @param operations the list of operations that will be added to
+ */
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+ operations.add(new CanvasOperations());
+ }
+
+ /**
+ * Populate the documentation with a description of this operation
+ *
+ * @param doc to append the description to.
+ */
+ public static void documentation(@NonNull DocumentationBuilder doc) {
+ doc.operation("Operations", OP_CODE, name())
+ .description("Impulse Process that runs a list of operations");
+ }
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("list", mList);
+ }
+
+ /**
+ * Set layout component
+ *
+ * @param layoutComponent
+ */
+ public void setComponent(LayoutComponent layoutComponent) {
+ mComponent = layoutComponent;
+ for (Operation op : mList) {
+ if (op instanceof DrawContent) {
+ ((DrawContent) op).setComponent(layoutComponent);
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
index e332e4be4c8d..c73643682b55 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
@@ -329,6 +329,15 @@ public class Component extends PaintOperation
mAnimationSpec = animationSpec;
}
+ /**
+ * If the component contains variables beside mList, make sure to register them here
+ *
+ * @param context
+ */
+ public void registerVariables(RemoteContext context) {
+ // Nothing here
+ }
+
public enum Visibility {
GONE,
VISIBLE,
@@ -976,6 +985,17 @@ public class Component extends PaintOperation
}
}
+ /** Extract CanvasOperations if present */
+ public @Nullable CanvasOperations getCanvasOperations(LayoutComponent layoutComponent) {
+ for (Operation op : mList) {
+ if (op instanceof CanvasOperations) {
+ ((CanvasOperations) op).setComponent(layoutComponent);
+ return (CanvasOperations) op;
+ }
+ }
+ return null;
+ }
+
/**
* Extract child TextData elements
*
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java
index f896f3d8ee9c..8c9dd76c9ed5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ImpulseProcess.java
@@ -25,12 +25,15 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.ArrayList;
import java.util.List;
/** Represents the repeating part of an Impulse. */
-public class ImpulseProcess extends PaintOperation implements VariableSupport, Container {
+public class ImpulseProcess extends PaintOperation
+ implements VariableSupport, Container, Serializable {
private static final int OP_CODE = Operations.IMPULSE_PROCESS;
private static final String CLASS_NAME = "ImpulseProcess";
@@ -151,4 +154,9 @@ public class ImpulseProcess extends PaintOperation implements VariableSupport, C
public int estimateIterations() {
return 1;
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("list", mList);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
index 10cbd4ca2a50..7e2a4ccec222 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
@@ -75,6 +75,7 @@ public class LayoutComponent extends Component {
protected ArrayList<Component> mChildrenComponents = new ArrayList<>(); // members are not null
protected boolean mChildrenHaveZIndex = false;
+ private CanvasOperations mDrawContentOperations;
public LayoutComponent(
@Nullable Component parent,
@@ -138,6 +139,7 @@ public class LayoutComponent extends Component {
mChildrenComponents.clear();
LayoutComponentContent content = (LayoutComponentContent) op;
content.getComponents(mChildrenComponents);
+ mDrawContentOperations = content.getCanvasOperations(this);
if (USE_IMAGE_TEMP_FIX) {
if (mChildrenComponents.isEmpty() && !mContent.mList.isEmpty()) {
CanvasContent canvasContent =
@@ -315,6 +317,31 @@ public class LayoutComponent extends Component {
}
@Override
+ public void paint(@NonNull PaintContext context) {
+ if (mDrawContentOperations != null) {
+ context.save();
+ context.translate(mX, mY);
+ mDrawContentOperations.paint(context);
+ context.restore();
+ return;
+ }
+ super.paint(context);
+ }
+
+ /**
+ * Paint the component content. Used by the DrawContent operation. (back out mX/mY -- TODO:
+ * refactor paintingComponent instead, to not include mX/mY etc.)
+ *
+ * @param context painting context
+ */
+ public void drawContent(@NonNull PaintContext context) {
+ context.save();
+ context.translate(-mX, -mY);
+ paintingComponent(context);
+ context.restore();
+ }
+
+ @Override
public void paintingComponent(@NonNull PaintContext context) {
Component prev = context.getContext().mLastComponent;
RemoteContext remoteContext = context.getContext();
@@ -514,4 +541,11 @@ public class LayoutComponent extends Component {
return null;
}
+
+ @Override
+ public void registerVariables(RemoteContext context) {
+ if (mDrawContentOperations != null) {
+ mDrawContentOperations.registerListening(context);
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
index 0f4cf562eae6..2b63cf246555 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
@@ -27,12 +27,16 @@ import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.Utils;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.ArrayList;
import java.util.List;
/** Represents a loop of operations */
-public class LoopOperation extends PaintOperation implements Container, VariableSupport {
+public class LoopOperation extends PaintOperation
+ implements Container, VariableSupport, Serializable {
+ private static final String CLASS_NAME = "LoopOperation";
private static final int OP_CODE = Operations.LOOP_START;
@@ -198,4 +202,16 @@ public class LoopOperation extends PaintOperation implements Container, Variable
}
return 10; // this is a generic estmate if the values are variables;
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", CLASS_NAME)
+ .add("indexVariableId", mIndexVariableId)
+ .add("until", mUntil, mUntilOut)
+ .add("from", mFrom, mFromOut)
+ .add("step", mStep, mStepOut)
+ .add("mUntilOut", mUntilOut)
+ .add("list", mList);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
index 1cfb50724e0b..d5db74b5ca51 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
@@ -209,7 +209,7 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
mPaint.setColor(mColor);
mPaint.setTextSize(mFontSize);
mPaint.setTextStyle(mType, (int) mFontWeight, mFontStyle == 1);
- context.applyPaint(mPaint);
+ context.replacePaint(mPaint);
if (mCachedString == null) {
return;
}
@@ -330,7 +330,7 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
mPaint.setTextSize(mFontSize);
mPaint.setTextStyle(mType, (int) mFontWeight, mFontStyle == 1);
mPaint.setColor(mColor);
- context.applyPaint(mPaint);
+ context.replacePaint(mPaint);
float[] bounds = new float[4];
if (mCachedString == null) {
return;
@@ -343,7 +343,7 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
flags |= PaintContext.TEXT_COMPLEX;
}
context.getTextBounds(mTextId, 0, mCachedString.length(), flags, bounds);
- if (bounds[2] - bounds[1] > maxWidth) {
+ if (bounds[2] - bounds[1] > maxWidth && mMaxLines > 1) {
mComputedTextLayout =
context.layoutComplexText(
mTextId,
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
index dc1b875f0f9c..fd5f8c9cdbe7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
@@ -196,7 +196,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation {
mPaint.reset();
mPaint.setStyle(PaintBundle.STYLE_FILL);
mPaint.setColor(mR, mG, mB, mA);
- context.applyPaint(mPaint);
+ context.replacePaint(mPaint);
if (mShapeType == ShapeType.RECTANGLE) {
context.drawRect(0f, 0f, mWidth, mHeight);
} else if (mShapeType == ShapeType.CIRCLE) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
index 3acbd88329c2..e5f318307a75 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
@@ -252,7 +252,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation {
paint.setColor(mR, mG, mB, mA);
paint.setStrokeWidth(mBorderWidth);
paint.setStyle(PaintBundle.STYLE_STROKE);
- context.applyPaint(paint);
+ context.replacePaint(paint);
if (mShapeType == ShapeType.RECTANGLE) {
context.drawRect(0f, 0f, mWidth, mHeight);
} else {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DrawContentOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DrawContentOperation.java
new file mode 100644
index 000000000000..d7abdbae4962
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DrawContentOperation.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.layout.modifiers;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent;
+import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent;
+import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.SerializeTags;
+
+import java.util.List;
+
+/** Represent a drawing of a component */
+public class DrawContentOperation extends Operation
+ implements ModifierOperation, VariableSupport, DecoratorComponent {
+ private static final int OP_CODE = Operations.MODIFIER_DRAW_CONTENT;
+
+ private LayoutComponent mParent;
+
+ public DrawContentOperation() {}
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "DrawContentOperation()";
+ }
+
+ /**
+ * Returns the serialized name for this operation
+ *
+ * @return the serialized name
+ */
+ @NonNull
+ public String serializedName() {
+ return "DRAW_CONTENT";
+ }
+
+ @Override
+ public void serializeToString(int indent, @NonNull StringSerializer serializer) {
+ serializer.append(indent, serializedName());
+ }
+
+ @Override
+ public void apply(@NonNull RemoteContext context) {}
+
+ @NonNull
+ @Override
+ public String deepToString(@NonNull String indent) {
+ return (indent != null ? indent : "") + toString();
+ }
+
+ @Override
+ public void write(@NonNull WireBuffer buffer) {}
+
+ /**
+ * Write the operation to the buffer
+ *
+ * @param buffer a WireBuffer
+ */
+ public static void apply(@NonNull WireBuffer buffer) {
+ buffer.start(OP_CODE);
+ }
+
+ /**
+ * Read this operation and add it to the list of operations
+ *
+ * @param buffer the buffer to read
+ * @param operations the list of operations that will be added to
+ */
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+ operations.add(new DrawContentOperation());
+ }
+
+ /**
+ * Populate the documentation with a description of this operation
+ *
+ * @param doc to append the description to.
+ */
+ public static void documentation(@NonNull DocumentationBuilder doc) {
+ doc.operation("Layout Operations", OP_CODE, "ComponentVisibility")
+ .description("This operation represents a draw of a component");
+ }
+
+ @Override
+ public void registerListening(@NonNull RemoteContext context) {}
+
+ @Override
+ public void updateVariables(@NonNull RemoteContext context) {}
+
+ public void setParent(@Nullable LayoutComponent parent) {
+ mParent = parent;
+ }
+
+ @Override
+ public void layout(
+ @NonNull RemoteContext context, Component component, float width, float height) {}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.addTags(SerializeTags.MODIFIER).add("type", "DrawContentOperation");
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java
index d3004aa73a77..69ace8478e08 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java
@@ -126,7 +126,7 @@ public class RippleModifierOperation extends DecoratorModifierOperation implemen
float radius = Math.max(mWidth, mHeight) * tweenRadius;
mPaint.setColor(paintedColor);
- context.applyPaint(mPaint);
+ context.replacePaint(mPaint);
context.clipRect(0f, 0f, mWidth, mHeight);
context.drawCircle(mAnimateRippleX, mAnimateRippleY, radius);
context.restorePaint();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
index 4c7f503e0bf8..0f17b114133d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
+import static com.android.internal.widget.remotecompose.core.serialize.MapSerializer.orderedOf;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -23,11 +25,16 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.operations.Utils;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
/** Paint Bundle represents a delta of changes to a paint object */
-public class PaintBundle {
+public class PaintBundle implements Serializable {
@NonNull int[] mArray = new int[200];
@Nullable int[] mOutArray = null;
int mPos = 0;
@@ -337,7 +344,6 @@ public class PaintBundle {
}
}
}
-
len = array[ret++]; // stops
for (int j = 0; j < len; j++) {
registerFloat(array[ret++], context, support);
@@ -1239,4 +1245,201 @@ public class PaintBundle {
return ret;
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", "PaintBundle");
+ List<Map<String, Object>> list = new ArrayList<>();
+ int i = 0;
+ while (i < mPos) {
+ int cmd = mArray[i++];
+ int type = cmd & 0xFFFF;
+ switch (type) {
+ case TEXT_SIZE:
+ list.add(orderedOf("type", "TextSize", "size", getVariable(mArray[i++])));
+ break;
+ case TYPEFACE:
+ int style = (cmd >> 16);
+ float weight = (float) (style & 0x3ff);
+ boolean italic = (style >> 10) > 0;
+ int fontFamily = mArray[i++];
+ list.add(orderedOf("type", "FontFamily", "fontFamily", fontFamily));
+ list.add(orderedOf("type", "FontWeight", "weight", weight));
+ list.add(orderedOf("type", "TypeFace", "italic", italic));
+ break;
+ case COLOR:
+ list.add(orderedOf("type", "Color", "color", colorInt(mArray[i++])));
+ break;
+ case COLOR_ID:
+ list.add(orderedOf("type", "ColorId", "id", mArray[i++]));
+ break;
+ case STROKE_WIDTH:
+ list.add(orderedOf("type", "StrokeWidth", "width", getVariable(mArray[i++])));
+ break;
+ case STROKE_MITER:
+ list.add(orderedOf("type", "StrokeMiter", "miter", getVariable(mArray[i++])));
+ break;
+ case STROKE_CAP:
+ list.add(orderedOf("type", "StrokeCap", "cap", cmd >> 16));
+ break;
+ case STYLE:
+ list.add(orderedOf("type", "Style", "style", cmd >> 16));
+ break;
+ case COLOR_FILTER:
+ list.add(
+ orderedOf(
+ "type",
+ "ColorFilter",
+ "color",
+ colorInt(mArray[i++]),
+ "mode",
+ blendModeString(cmd >> 16)));
+ break;
+ case COLOR_FILTER_ID:
+ list.add(
+ orderedOf(
+ "type",
+ "ColorFilterID",
+ "id",
+ mArray[i++],
+ "mode",
+ blendModeString(cmd >> 16)));
+ break;
+ case CLEAR_COLOR_FILTER:
+ list.add(orderedOf("type", "ClearColorFilter"));
+ break;
+ case SHADER:
+ list.add(orderedOf("type", "Shader", "id", mArray[i++]));
+ break;
+ case ALPHA:
+ list.add(orderedOf("type", "Alpha", "alpha", getVariable(mArray[i++])));
+ break;
+ case IMAGE_FILTER_QUALITY:
+ list.add(orderedOf("type", "ImageFilterQuality", "quality", cmd >> 16));
+ break;
+ case BLEND_MODE:
+ list.add(orderedOf("type", "BlendMode", "mode", blendModeString(cmd >> 16)));
+ break;
+ case FILTER_BITMAP:
+ list.add(orderedOf("type", "FilterBitmap", "enabled", !(cmd >> 16 == 0)));
+ break;
+ case STROKE_JOIN:
+ list.add(orderedOf("type", "StrokeJoin", "strokeJoin", cmd >> 16));
+ break;
+ case ANTI_ALIAS:
+ list.add(orderedOf("type", "AntiAlias", "enabled", !(cmd >> 16 == 0)));
+ break;
+ case GRADIENT:
+ i = serializeGradient(cmd, mArray, i, list);
+ }
+ }
+ serializer.add("operations", list);
+ }
+
+ private static Map<String, Object> getVariable(int value) {
+ float fValue = Float.intBitsToFloat(value);
+ if (Float.isNaN(fValue)) {
+ return orderedOf("type", "Variable", "id", Utils.idFromNan(fValue));
+ }
+ return orderedOf("type", "Value", "value", fValue);
+ }
+
+ private static int serializeGradient(
+ int cmd, int[] array, int i, List<Map<String, Object>> list) {
+ int ret = i;
+ int gradientType = (cmd >> 16);
+
+ int len = 0xFF & array[ret++]; // maximum 256 colors
+
+ String[] colors = null;
+ if (len > 0) {
+ colors = new String[len];
+ for (int j = 0; j < colors.length; j++) {
+ colors[j] = colorInt(array[ret++]);
+ }
+ }
+ len = array[ret++];
+ float[] stops = null;
+ if (len > 0) {
+ stops = new float[len];
+ for (int j = 0; j < colors.length; j++) {
+ stops[j] = Float.intBitsToFloat(array[ret++]);
+ }
+ }
+
+ if (colors == null) {
+ return ret;
+ }
+
+ int tileMode;
+ int centerX;
+ int centerY;
+
+ switch (gradientType) {
+ case LINEAR_GRADIENT:
+ int startX = array[ret++];
+ int startY = array[ret++];
+ int endX = array[ret++];
+ int endY = array[ret++];
+ tileMode = array[ret++];
+ list.add(
+ orderedOf(
+ "type",
+ "LinearGradient",
+ "colors",
+ colors,
+ "stops",
+ stops == null ? List.of() : stops,
+ "startX",
+ getVariable(startX),
+ "startY",
+ getVariable(startY),
+ "endX",
+ getVariable(endX),
+ "endY",
+ getVariable(endY),
+ "tileMode",
+ tileMode));
+ break;
+ case RADIAL_GRADIENT:
+ centerX = array[ret++];
+ centerY = array[ret++];
+ int radius = array[ret++];
+ tileMode = array[ret++];
+ list.add(
+ orderedOf(
+ "type",
+ "LinearGradient",
+ "colors",
+ colors,
+ "stops",
+ stops == null ? List.of() : stops,
+ "centerX",
+ getVariable(centerX),
+ "centerY",
+ getVariable(centerY),
+ "radius",
+ getVariable(radius),
+ "tileMode",
+ tileMode));
+ break;
+ case SWEEP_GRADIENT:
+ centerX = array[ret++];
+ centerY = array[ret++];
+ list.add(
+ orderedOf(
+ "type",
+ "LinearGradient",
+ "colors",
+ colors,
+ "stops",
+ stops == null ? List.of() : stops,
+ "centerX",
+ getVariable(centerX),
+ "centerY",
+ getVariable(centerY)));
+ }
+
+ return ret;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
index 65472c262206..cad76059f7a4 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
@@ -18,8 +18,11 @@ package com.android.internal.widget.remotecompose.core.operations.utilities.easi
import android.annotation.NonNull;
import android.annotation.Nullable;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
+
/** Support Animation of the FloatExpression */
-public class FloatAnimation extends Easing {
+public class FloatAnimation extends Easing implements Serializable {
float[] mSpec;
// mSpec[0] = duration
// int(mSpec[1]) = num_of_param << 16 | type
@@ -391,4 +394,14 @@ public class FloatAnimation extends Easing {
public float getInitialValue() {
return mInitialValue;
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .add("type", "FloatAnimation")
+ .add("initialValue", mInitialValue)
+ .add("targetValue", mInitialValue)
+ .add("duration", mInitialValue)
+ .add("easing", Easing.getString(mEasingCurve.getType()));
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java b/core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java
index bcdac22f7baa..f9ecf0f4f672 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/serialize/MapSerializer.java
@@ -17,6 +17,7 @@ package com.android.internal.widget.remotecompose.core.serialize;
import android.annotation.Nullable;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -24,6 +25,24 @@ import java.util.Map;
public interface MapSerializer {
/**
+ * Add a float expression
+ *
+ * @param key
+ * @param value
+ * @return
+ */
+ MapSerializer addFloatExpressionSrc(String key, float[] value);
+
+ /**
+ * Add an int expression
+ *
+ * @param key The key
+ * @param value The int src
+ * @param mask For determining ID from int
+ */
+ MapSerializer addIntExpressionSrc(String key, int[] value, int mask);
+
+ /**
* Add metadata to this map for filtering by the data format generator.
*
* @param value A set of tags to add
@@ -146,4 +165,19 @@ public interface MapSerializer {
* @param value The Enum
*/
<T extends Enum<T>> MapSerializer add(String key, @Nullable Enum<T> value);
+
+ /**
+ * Similar to Map.of, but create a LinkedHashMap preserving insertion order for predictable
+ * serialization.
+ *
+ * @param keysAndValues a even number of items, repeating String key and Object value.
+ * @return A LinkedHashMap.
+ */
+ static LinkedHashMap<String, Object> orderedOf(Object... keysAndValues) {
+ final LinkedHashMap<String, Object> map = new LinkedHashMap<>();
+ for (int i = 0; i < keysAndValues.length; i += 2) {
+ map.put((String) keysAndValues[i], keysAndValues[i + 1]);
+ }
+ return map;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/serialize/SerializeTags.java b/core/java/com/android/internal/widget/remotecompose/core/serialize/SerializeTags.java
index 99cac0fc75a8..c29dd98fbd7d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/serialize/SerializeTags.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/serialize/SerializeTags.java
@@ -22,4 +22,5 @@ public enum SerializeTags {
A11Y,
ACTION,
DRAW_OPERATION,
+ EXPRESSION,
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
index 2c874b183a62..cb759a61249a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
@@ -25,11 +25,15 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Used to represent a boolean */
-public class BooleanConstant extends Operation {
+public class BooleanConstant extends Operation implements Serializable {
+ private static final String CLASS_NAME = "BooleanConstant";
+
private static final int OP_CODE = Operations.DATA_BOOLEAN;
private boolean mValue = false;
private int mId;
@@ -124,4 +128,9 @@ public class BooleanConstant extends Operation {
.field(DocumentedOperation.INT, "id", "id of Int")
.field(BYTE, "value", "8-bit 0 or 1");
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("id", mId).add("value", mValue);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
index 5462d3e069ed..c734f813ede3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
@@ -25,13 +25,17 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Represents a single integer typically used for states or named for input into the system */
-public class IntegerConstant extends Operation {
- private int mValue = 0;
- private int mId;
+public class IntegerConstant extends Operation implements Serializable {
+ private static final String CLASS_NAME = "IntegerConstant";
+
+ private final int mValue;
+ private final int mId;
IntegerConstant(int id, int value) {
mId = id;
@@ -116,4 +120,9 @@ public class IntegerConstant extends Operation {
.field(DocumentedOperation.INT, "id", "id of Int")
.field(INT, "value", "32-bit int value");
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("id", mId).add("value", mValue);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
index 1a3cdb1a96d7..50509f3636b3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
@@ -25,14 +25,18 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Used to represent a long */
-public class LongConstant extends Operation {
+public class LongConstant extends Operation implements Serializable {
+ private static final String CLASS_NAME = "LongConstant";
+
private static final int OP_CODE = Operations.DATA_LONG;
- private long mValue;
- private int mId;
+ private final long mValue;
+ private final int mId;
public LongConstant(int id, long value) {
mId = id;
@@ -107,4 +111,9 @@ public class LongConstant extends Operation {
.field(DocumentedOperation.INT, "id", "id of Int")
.field(LONG, "value", "The long Value");
}
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.add("type", CLASS_NAME).add("id", mId).add("value", mValue);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
index 77f4b6a83eef..1d1e579ebc2f 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
@@ -29,7 +29,6 @@ import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
-import android.view.HapticFeedbackConstants;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
@@ -596,29 +595,34 @@ public class RemoteComposePlayer extends FrameLayout implements RemoteContextAwa
}
}
- private static int[] sHapticTable = {
- HapticFeedbackConstants.NO_HAPTICS,
- HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.VIRTUAL_KEY,
- HapticFeedbackConstants.KEYBOARD_TAP,
- HapticFeedbackConstants.CLOCK_TICK,
- HapticFeedbackConstants.CONTEXT_CLICK,
- HapticFeedbackConstants.KEYBOARD_PRESS,
- HapticFeedbackConstants.KEYBOARD_RELEASE,
- HapticFeedbackConstants.VIRTUAL_KEY_RELEASE,
- HapticFeedbackConstants.TEXT_HANDLE_MOVE,
- HapticFeedbackConstants.GESTURE_START,
- HapticFeedbackConstants.GESTURE_END,
- HapticFeedbackConstants.CONFIRM,
- HapticFeedbackConstants.REJECT,
- HapticFeedbackConstants.TOGGLE_ON,
- HapticFeedbackConstants.TOGGLE_OFF,
- HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE,
- HapticFeedbackConstants.GESTURE_THRESHOLD_DEACTIVATE,
- HapticFeedbackConstants.DRAG_START,
- HapticFeedbackConstants.SEGMENT_TICK,
- HapticFeedbackConstants.SEGMENT_FREQUENT_TICK,
- };
+ private static final int[] sHapticTable;
+
+ static {
+ sHapticTable =
+ new int[] {
+ android.view.HapticFeedbackConstants.NO_HAPTICS,
+ android.view.HapticFeedbackConstants.LONG_PRESS,
+ android.view.HapticFeedbackConstants.VIRTUAL_KEY,
+ android.view.HapticFeedbackConstants.KEYBOARD_TAP,
+ android.view.HapticFeedbackConstants.CLOCK_TICK,
+ android.view.HapticFeedbackConstants.CONTEXT_CLICK,
+ android.view.HapticFeedbackConstants.KEYBOARD_PRESS,
+ android.view.HapticFeedbackConstants.KEYBOARD_RELEASE,
+ android.view.HapticFeedbackConstants.VIRTUAL_KEY_RELEASE,
+ android.view.HapticFeedbackConstants.TEXT_HANDLE_MOVE,
+ android.view.HapticFeedbackConstants.GESTURE_START,
+ android.view.HapticFeedbackConstants.GESTURE_END,
+ android.view.HapticFeedbackConstants.CONFIRM,
+ android.view.HapticFeedbackConstants.REJECT,
+ android.view.HapticFeedbackConstants.TOGGLE_ON,
+ android.view.HapticFeedbackConstants.TOGGLE_OFF,
+ android.view.HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE,
+ android.view.HapticFeedbackConstants.GESTURE_THRESHOLD_DEACTIVATE,
+ android.view.HapticFeedbackConstants.DRAG_START,
+ android.view.HapticFeedbackConstants.SEGMENT_TICK,
+ android.view.HapticFeedbackConstants.SEGMENT_FREQUENT_TICK,
+ };
+ }
private void provideHapticFeedback(int type) {
performHapticFeedback(sHapticTable[type % sHapticTable.length]);
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index 6b1a30a7545c..ac4a294b5e5e 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -246,6 +246,12 @@ public class AndroidPaintContext extends PaintContext {
}
@Override
+ public void replacePaint(PaintBundle paintBundle) {
+ mPaint.reset();
+ applyPaint(paintBundle);
+ }
+
+ @Override
public void drawRoundRect(
float left, float top, float right, float bottom, float radiusX, float radiusY) {
mCanvas.drawRoundRect(left, top, right, bottom, radiusX, radiusY, mPaint);
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
index f76794fc0372..4d2dd05ca603 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
@@ -31,6 +31,7 @@ import android.widget.FrameLayout;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.operations.Header;
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.core.operations.Theme;
import com.android.internal.widget.remotecompose.player.RemoteComposeDocument;
@@ -105,10 +106,16 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta
mARContext.setDensity(mDensity);
mARContext.setUseChoreographer(true);
setContentDescription(mDocument.getDocument().getContentDescription());
+
updateClickAreas();
requestLayout();
mARContext.loadFloat(RemoteContext.ID_TOUCH_EVENT_TIME, -Float.MAX_VALUE);
invalidate();
+ Integer fps = (Integer) mDocument.getDocument().getProperty(Header.DOC_DESIRED_FPS);
+ if (fps != null && fps > 0) {
+ mMaxFrameRate = fps;
+ mMaxFrameDelay = (long) (1000 / mMaxFrameRate);
+ }
}
@Override
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 447822f0903f..06702e2fa4bf 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -134,6 +134,10 @@ cc_library_shared_for_libandroid_runtime {
"android_app_ActivityThread.cpp",
"android_app_NativeActivity.cpp",
"android_app_admin_SecurityLog.cpp",
+ "android_media_ImageReader.cpp",
+ "android_media_ImageWriter.cpp",
+ "android_media_PublicFormatUtils.cpp",
+ "android_media_Utils.cpp",
"android_opengl_EGL14.cpp",
"android_opengl_EGL15.cpp",
"android_opengl_EGLExt.cpp",
@@ -531,3 +535,35 @@ cc_library_shared {
"vintf",
],
}
+
+cc_library_shared {
+ name: "libmedia_jni_utils",
+ srcs: [
+ ":libgui_frame_event_aidl",
+ "android_media_Utils.cpp",
+ ],
+
+ header_libs: [
+ "libgui_headers",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+
+ include_dirs: [
+ "system/media/camera/include",
+ ],
+
+ export_include_dirs: ["."],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 5c0b72013a06..b2b826391e1d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -102,7 +102,10 @@ extern int register_android_media_AudioAttributes(JNIEnv *env);
extern int register_android_media_AudioProductStrategies(JNIEnv *env);
extern int register_android_media_AudioVolumeGroups(JNIEnv *env);
extern int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env);
+extern int register_android_media_ImageReader(JNIEnv *env);
+extern int register_android_media_ImageWriter(JNIEnv *env);
extern int register_android_media_MicrophoneInfo(JNIEnv *env);
+extern int register_android_media_PublicFormatUtils(JNIEnv *env);
extern int register_android_media_ToneGenerator(JNIEnv *env);
extern int register_android_media_audio_common_AidlConversion(JNIEnv* env);
extern int register_android_media_midi(JNIEnv *env);
@@ -1658,8 +1661,11 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_media_AudioProductStrategies),
REG_JNI(register_android_media_AudioVolumeGroups),
REG_JNI(register_android_media_AudioVolumeGroupChangeHandler),
+ REG_JNI(register_android_media_ImageReader),
+ REG_JNI(register_android_media_ImageWriter),
REG_JNI(register_android_media_MediaMetrics),
REG_JNI(register_android_media_MicrophoneInfo),
+ REG_JNI(register_android_media_PublicFormatUtils),
REG_JNI(register_android_media_RemoteDisplay),
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_media_audio_common_AidlConversion),
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index 1e7bfe32ba79..66c65d0ac1aa 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -111,9 +111,8 @@ static void DeleteGuardedApkAssets(Guarded<AssetManager2::ApkAssetsPtr>& apk_ass
class LoaderAssetsProvider : public AssetsProvider {
public:
static std::unique_ptr<AssetsProvider> Create(JNIEnv* env, jobject assets_provider) {
- return (!assets_provider) ? EmptyAssetsProvider::Create()
- : std::unique_ptr<AssetsProvider>(new LoaderAssetsProvider(
- env, assets_provider));
+ return std::unique_ptr<AssetsProvider>{
+ assets_provider ? new LoaderAssetsProvider(env, assets_provider) : nullptr};
}
bool ForEachFile(const std::string& /* root_path */,
@@ -129,8 +128,8 @@ class LoaderAssetsProvider : public AssetsProvider {
return debug_name_;
}
- bool IsUpToDate() const override {
- return true;
+ UpToDate IsUpToDate() const override {
+ return UpToDate::Always;
}
~LoaderAssetsProvider() override {
@@ -212,7 +211,7 @@ class LoaderAssetsProvider : public AssetsProvider {
auto string_result = static_cast<jstring>(env->CallObjectMethod(
assets_provider_, gAssetsProviderOffsets.toString));
ScopedUtfChars str(env, string_result);
- debug_name_ = std::string(str.c_str(), str.size());
+ debug_name_ = std::string(str.c_str());
}
// The global reference to the AssetsProvider
@@ -233,9 +232,9 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma
AssetManager2::ApkAssetsPtr apk_assets;
switch (format) {
case FORMAT_APK: {
- auto assets = MultiAssetsProvider::Create(std::move(loader_assets),
- ZipAssetsProvider::Create(path.c_str(),
- property_flags));
+ auto assets = AssetsProvider::CreateWithOverride(ZipAssetsProvider::Create(path.c_str(),
+ property_flags),
+ std::move(loader_assets));
apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
}
@@ -243,15 +242,17 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma
apk_assets = ApkAssets::LoadOverlay(path.c_str(), property_flags);
break;
case FORMAT_ARSC:
- apk_assets = ApkAssets::LoadTable(AssetsProvider::CreateAssetFromFile(path.c_str()),
- std::move(loader_assets),
- property_flags);
- break;
+ apk_assets =
+ ApkAssets::LoadTable(AssetsProvider::CreateAssetFromFile(path.c_str()),
+ AssetsProvider::CreateFromNullable(std::move(loader_assets)),
+ property_flags);
+ break;
case FORMAT_DIRECTORY: {
- auto assets = MultiAssetsProvider::Create(std::move(loader_assets),
- DirectoryAssetsProvider::Create(path.c_str()));
- apk_assets = ApkAssets::Load(std::move(assets), property_flags);
- break;
+ auto assets =
+ AssetsProvider::CreateWithOverride(DirectoryAssetsProvider::Create(path.c_str()),
+ std::move(loader_assets));
+ apk_assets = ApkAssets::Load(std::move(assets), property_flags);
+ break;
}
default:
const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
@@ -308,18 +309,21 @@ static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, const format_type_t
switch (format) {
case FORMAT_APK: {
auto assets =
- MultiAssetsProvider::Create(std::move(loader_assets),
- ZipAssetsProvider::Create(std::move(dup_fd),
- friendly_name_utf8.c_str(),
- property_flags));
+ AssetsProvider::CreateWithOverride(ZipAssetsProvider::Create(std::move(dup_fd),
+ friendly_name_utf8
+ .c_str(),
+ property_flags),
+ std::move(loader_assets));
apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
}
case FORMAT_ARSC:
- apk_assets = ApkAssets::LoadTable(
- AssetsProvider::CreateAssetFromFd(std::move(dup_fd), nullptr /* path */),
- std::move(loader_assets), property_flags);
- break;
+ apk_assets =
+ ApkAssets::LoadTable(AssetsProvider::CreateAssetFromFd(std::move(dup_fd),
+ nullptr /* path */),
+ AssetsProvider::CreateFromNullable(std::move(loader_assets)),
+ property_flags);
+ break;
default:
const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
@@ -375,23 +379,28 @@ static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_
switch (format) {
case FORMAT_APK: {
auto assets =
- MultiAssetsProvider::Create(std::move(loader_assets),
- ZipAssetsProvider::Create(std::move(dup_fd),
- friendly_name_utf8.c_str(),
- property_flags,
- static_cast<off64_t>(offset),
- static_cast<off64_t>(
- length)));
+ AssetsProvider::CreateWithOverride(ZipAssetsProvider::Create(std::move(dup_fd),
+ friendly_name_utf8
+ .c_str(),
+ property_flags,
+ static_cast<off64_t>(
+ offset),
+ static_cast<off64_t>(
+ length)),
+ std::move(loader_assets));
apk_assets = ApkAssets::Load(std::move(assets), property_flags);
break;
}
case FORMAT_ARSC:
- apk_assets = ApkAssets::LoadTable(
- AssetsProvider::CreateAssetFromFd(std::move(dup_fd), nullptr /* path */,
- static_cast<off64_t>(offset),
- static_cast<off64_t>(length)),
- std::move(loader_assets), property_flags);
- break;
+ apk_assets =
+ ApkAssets::LoadTable(AssetsProvider::CreateAssetFromFd(std::move(dup_fd),
+ nullptr /* path */,
+ static_cast<off64_t>(offset),
+ static_cast<off64_t>(
+ length)),
+ AssetsProvider::CreateFromNullable(std::move(loader_assets)),
+ property_flags);
+ break;
default:
const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
@@ -408,13 +417,16 @@ static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_
}
static jlong NativeLoadEmpty(JNIEnv* env, jclass /*clazz*/, jint flags, jobject assets_provider) {
- auto apk_assets = ApkAssets::Load(LoaderAssetsProvider::Create(env, assets_provider), flags);
- if (apk_assets == nullptr) {
- const std::string error_msg =
- base::StringPrintf("Failed to load empty assets with provider %p", (void*)assets_provider);
- jniThrowException(env, "java/io/IOException", error_msg.c_str());
- return 0;
- }
+ auto apk_assets = ApkAssets::Load(AssetsProvider::CreateFromNullable(
+ LoaderAssetsProvider::Create(env, assets_provider)),
+ flags);
+ if (apk_assets == nullptr) {
+ const std::string error_msg =
+ base::StringPrintf("Failed to load empty assets with provider %p",
+ (void*)assets_provider);
+ jniThrowException(env, "java/io/IOException", error_msg.c_str());
+ return 0;
+ }
return CreateGuardedApkAssets(std::move(apk_assets));
}
@@ -443,10 +455,10 @@ static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr)
return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool());
}
-static jboolean NativeIsUpToDate(CRITICAL_JNI_PARAMS_COMMA jlong ptr) {
+static jint NativeIsUpToDate(CRITICAL_JNI_PARAMS_COMMA jlong ptr) {
auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr));
auto apk_assets = scoped_apk_assets->get();
- return apk_assets->IsUpToDate() ? JNI_TRUE : JNI_FALSE;
+ return (jint)apk_assets->IsUpToDate();
}
static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) {
@@ -558,7 +570,7 @@ static const JNINativeMethod gApkAssetsMethods[] = {
{"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName},
{"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
// @CriticalNative
- {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
+ {"nativeIsUpToDate", "(J)I", (void*)NativeIsUpToDate},
{"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
{"nativeGetOverlayableInfo", "(JLjava/lang/String;)Landroid/content/om/OverlayableInfo;",
(void*)NativeGetOverlayableInfo},
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 102edc944c22..22298b3f9525 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -598,7 +598,7 @@ static jintArray android_media_AudioRecord_getRoutedDeviceIds(JNIEnv *env, jobje
}
jint *values = env->GetIntArrayElements(result, 0);
for (unsigned int i = 0; i < deviceIds.size(); i++) {
- values[i++] = static_cast<jint>(deviceIds[i]);
+ values[i] = static_cast<jint>(deviceIds[i]);
}
env->ReleaseIntArrayElements(result, values, 0);
return result;
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 2ba6bc4912c3..b679688959b1 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -664,14 +664,16 @@ static void android_media_AudioSystem_vol_range_init_req_callback()
static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz,
jint state, jobject jParcel,
- jint codec) {
+ jint codec, jboolean deviceSwitch) {
int status;
if (Parcel *parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
android::media::audio::common::AudioPort port{};
if (status_t statusOfParcel = port.readFromParcel(parcel); statusOfParcel == OK) {
- status = check_AudioSystem_Command(
- AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>(state),
- port, static_cast<audio_format_t>(codec)));
+ status = check_AudioSystem_Command(
+ AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>(
+ state),
+ port, static_cast<audio_format_t>(codec),
+ deviceSwitch));
} else {
ALOGE("Failed to read from parcel: %s", statusToString(statusOfParcel).c_str());
status = kAudioStatusError;
@@ -3457,7 +3459,7 @@ static const JNINativeMethod gMethods[] = {
MAKE_AUDIO_SYSTEM_METHOD(newAudioSessionId),
MAKE_AUDIO_SYSTEM_METHOD(newAudioPlayerId),
MAKE_AUDIO_SYSTEM_METHOD(newAudioRecorderId),
- MAKE_JNI_NATIVE_METHOD("setDeviceConnectionState", "(ILandroid/os/Parcel;I)I",
+ MAKE_JNI_NATIVE_METHOD("setDeviceConnectionState", "(ILandroid/os/Parcel;IZ)I",
android_media_AudioSystem_setDeviceConnectionState),
MAKE_AUDIO_SYSTEM_METHOD(getDeviceConnectionState),
MAKE_AUDIO_SYSTEM_METHOD(handleDeviceConfigChange),
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 3fc1a02f46b6..3cf5d5fdde24 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1204,7 +1204,7 @@ static jintArray android_media_AudioTrack_getRoutedDeviceIds(JNIEnv *env, jobjec
}
jint *values = env->GetIntArrayElements(result, 0);
for (unsigned int i = 0; i < deviceIds.size(); i++) {
- values[i++] = static_cast<jint>(deviceIds[i]);
+ values[i] = static_cast<jint>(deviceIds[i]);
}
env->ReleaseIntArrayElements(result, values, 0);
return result;
diff --git a/media/jni/android_media_ImageReader.cpp b/core/jni/android_media_ImageReader.cpp
index effa92c5f2fa..20b9c571317e 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/core/jni/android_media_ImageReader.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#undef ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION // TODO:remove this and fix code
//#define LOG_NDEBUG 0
#define LOG_TAG "ImageReader_JNI"
diff --git a/media/jni/android_media_ImageWriter.cpp b/core/jni/android_media_ImageWriter.cpp
index 93deb51df142..1357dd842ff1 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/core/jni/android_media_ImageWriter.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#undef ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION // TODO:remove this and fix code
//#define LOG_NDEBUG 0
#define LOG_TAG "ImageWriter_JNI"
diff --git a/media/jni/android_media_PublicFormatUtils.cpp b/core/jni/android_media_PublicFormatUtils.cpp
index 04494ad00a65..04494ad00a65 100644
--- a/media/jni/android_media_PublicFormatUtils.cpp
+++ b/core/jni/android_media_PublicFormatUtils.cpp
diff --git a/media/jni/android_media_Utils.cpp b/core/jni/android_media_Utils.cpp
index e8f8644a4503..e8f8644a4503 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/core/jni/android_media_Utils.cpp
diff --git a/media/jni/android_media_Utils.h b/core/jni/android_media_Utils.h
index c12cec129ede..c12cec129ede 100644
--- a/media/jni/android_media_Utils.h
+++ b/core/jni/android_media_Utils.h
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index e0cc055a62a6..c4259f41e380 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -266,16 +266,24 @@ class NativeCommandBuffer {
}
// Picky version of atoi(). No sign or unexpected characters allowed. Return -1 on failure.
static int digitsVal(char* start, char* end) {
+ constexpr int vmax = std::numeric_limits<int>::max();
int result = 0;
- if (end - start > 6) {
- return -1;
- }
for (char* dp = start; dp < end; ++dp) {
if (*dp < '0' || *dp > '9') {
- ALOGW("Argument failed integer format check");
+ ALOGW("Argument contains non-integer characters");
+ return -1;
+ }
+ int digit = *dp - '0';
+ if (result > vmax / 10) {
+ ALOGW("Argument exceeds int limit");
+ return -1;
+ }
+ result *= 10;
+ if (result > vmax - digit) {
+ ALOGW("Argument exceeds int limit");
return -1;
}
- result = 10 * result + (*dp - '0');
+ result += digit;
}
return result;
}
diff --git a/core/proto/android/nfc/OWNERS b/core/proto/android/nfc/OWNERS
index ca16721eacc1..36823aee4dbb 100644
--- a/core/proto/android/nfc/OWNERS
+++ b/core/proto/android/nfc/OWNERS
@@ -1 +1 @@
-include platform/packages/apps/Nfc:/OWNERS \ No newline at end of file
+include platform/packages/modules/Nfc:/OWNERS \ No newline at end of file
diff --git a/core/res/Android.bp b/core/res/Android.bp
index be4fb8bdecfb..1199d77d04c6 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -174,6 +174,7 @@ android_app {
"android.media.tv.flags-aconfig",
"android.security.flags-aconfig",
"device_policy_aconfig_flags",
+ "android.xr.flags-aconfig",
"com.android.hardware.input.input-aconfig",
"aconfig_trade_in_mode_flags",
"art-aconfig-flags",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 51049889ecd6..78526ad4a06b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5230,6 +5230,182 @@
android:protectionLevel="signature|privileged" />
<!-- ==================================== -->
+ <!-- Permissions for XR perception data -->
+ <!-- ==================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated with accessing XR
+ tracked information about the person using the device and the
+ environment around them.
+
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) -->
+ <permission-group android:name="android.permission-group.XR_TRACKING"
+ android:label="@string/permgrouplab_xr_tracking"
+ android:description="@string/permgroupdesc_xr_tracking"
+ android:priority="100"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to get approximate eye gaze.
+
+ <p>Protection level: dangerous
+
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) -->
+ <permission android:name="android.permission.EYE_TRACKING_COARSE"
+ android:protectionLevel="dangerous"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_eye_tracking_coarse"
+ android:description="@string/permdesc_eye_tracking_coarse"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to get face tracking data.
+
+ <p>Protection level: dangerous
+
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) -->
+ <permission android:name="android.permission.FACE_TRACKING"
+ android:protectionLevel="dangerous"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_face_tracking"
+ android:description="@string/permdesc_face_tracking"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to get hand tracking data.
+
+ <p>Protection level: dangerous
+
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) -->
+ <permission android:name="android.permission.HAND_TRACKING"
+ android:protectionLevel="dangerous"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_hand_tracking"
+ android:description="@string/permdesc_hand_tracking"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to get data derived by sensing the
+ user's environment.
+
+ <p>Protection level: dangerous
+
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) -->
+ <permission android:name="android.permission.SCENE_UNDERSTANDING_COARSE"
+ android:protectionLevel="dangerous"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_scene_understanding_coarse"
+ android:label="@string/permlab_scene_understanding_coarse"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Used for permissions that are associated with accessing
+ particularly sensitive XR tracking data.
+
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) -->
+ <permission-group android:name="android.permission-group.XR_TRACKING_SENSITIVE"
+ android:label="@string/permgrouplab_xr_tracking_sensitive"
+ android:description="@string/permgroupdesc_xr_tracking_sensitive"
+ android:priority="100"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to get precise eye gaze data.
+
+ <p>Protection level: dangerous
+
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) -->
+ <permission android:name="android.permission.EYE_TRACKING_FINE"
+ android:protectionLevel="dangerous"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_eye_tracking_fine"
+ android:description="@string/permdesc_eye_tracking_fine"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to get head tracking data. Unmanaged
+ activities (OpenXR activities with the manifest property
+ "android.window.PROPERTY_XR_ACTIVITY_START_MODE" set to
+ "XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED") do not require
+ this permission to get head tracking data.
+
+ {@see https://developer.android.com/develop/xr/get-started#property_activity_xr_start_mode_property}
+
+ <p>Protection level: dangerous
+
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) -->
+ <permission android:name="android.permission.HEAD_TRACKING"
+ android:protectionLevel="dangerous"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_head_tracking"
+ android:description="@string/permdesc_head_tracking"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to get highly precise data derived by sensing the
+ user's environment, such as a depth map.
+
+ <p>Protection level: dangerous
+
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) -->
+ <permission android:name="android.permission.SCENE_UNDERSTANDING_FINE"
+ android:protectionLevel="dangerous"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_scene_understanding_fine"
+ android:label="@string/permlab_scene_understanding_fine"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to trigger Eye Calibration, which
+ calibrates for IPD (inter-pupillary distance) adjustment and
+ eye tracking.
+
+ <p>Protection level: signature|privileged
+
+ @SystemApi
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+ @hide -->
+ <permission android:name="android.permission.EYE_CALIBRATION"
+ android:protectionLevel="signature|privileged"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to trigger Face Tracking Calibration.
+
+ <p>Protection level: signature|privileged
+
+ @SystemApi
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+ @hide -->
+ <permission android:name="android.permission.FACE_TRACKING_CALIBRATION"
+ android:protectionLevel="signature|privileged"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to import an anchor created and
+ exported by another application.
+
+ <p>Protection level: signature|privileged
+
+ @SystemApi
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+ @hide -->
+ <permission android:name="android.permission.IMPORT_XR_ANCHOR"
+ android:protectionLevel="signature|privileged"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- Allows an application to access XR tracking data while in the
+ background. Without this permission, XR tracking data such as
+ head tracking, hand tracking, eye tracking, or face tracking
+ is only available to an activity it is in the
+ foreground. With this permission, such data is also available
+ to services and to activities that are in the background.
+
+ <p>This permission must be granted in addition to the
+ corresponding permission such as {@link #HEAD_TRACKING} or
+ {@link #FACE_TRACKING} for the data being accessed.
+
+ <p>Protection level: normal|appop
+
+ @SystemApi
+ @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+ @hide -->
+ <permission android:name="android.permission.XR_TRACKING_IN_BACKGROUND"
+ android:protectionLevel="normal|appop"
+ android:description="@string/permdesc_xr_tracking_in_background"
+ android:label="@string/permlab_xr_tracking_in_background"
+ android:featureFlag="android.xr.xr_manifest_entries" />
+
+ <!-- ==================================== -->
<!-- Private permissions -->
<!-- ==================================== -->
<eat-comment />
@@ -7688,12 +7864,12 @@
<permission android:name="android.permission.ACCESS_SMARTSPACE"
android:protectionLevel="signature|privileged|development" />
- <!-- @SystemApi Allows an application to start a contextual search.
- @FlaggedApi("android.app.contextualsearch.flags.enable_service")
- @hide <p>Not for use by third-party applications.</p> -->
+ <!-- @SystemApi Allows a system application to start a contextual search.
+ Other applications can start a contextual search only if they have a
+ foreground activity.
+ @hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.ACCESS_CONTEXTUAL_SEARCH"
- android:protectionLevel="signature|privileged"
- android:featureFlag="android.app.contextualsearch.flags.enable_service"/>
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to manage the wallpaper effects
generation service.
diff --git a/core/res/res/drawable-w192dp/loader_horizontal_watch.xml b/core/res/res/drawable-w192dp/loader_horizontal_watch.xml
new file mode 100644
index 000000000000..18cea6e0d87d
--- /dev/null
+++ b/core/res/res/drawable-w192dp/loader_horizontal_watch.xml
@@ -0,0 +1,97 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="15dp" android:width="67dp" android:viewportHeight="15" android:viewportWidth="67">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G" android:translateX="33.5" android:translateY="7.5">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M33.5 -7.5 C33.5,-7.5 33.5,7.5 33.5,7.5 C33.5,7.5 -33.5,7.5 -33.5,7.5 C-33.5,7.5 -33.5,-7.5 -33.5,-7.5 C-33.5,-7.5 33.5,-7.5 33.5,-7.5c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="-296.5" android:translateY="-62.5" android:pivotX="330" android:pivotY="70" android:scaleX="0.1" android:scaleY="0.1">
+ <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-224.84700000000004" android:translateY="-321.948" android:pivotX="555.09" android:pivotY="-329" android:rotation="28.9" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M194.88 359 C190,359 185.05,357.81 180.48,355.3 C59.86,289.14 -41.55,191.9 -112.79,74.11 C-186.14,-47.16 -224.91,-186.55 -224.91,-329 C-224.91,-345.57 -211.48,-359 -194.91,-359 C-178.34,-359 -164.91,-345.57 -164.91,-329 C-164.91,-197.5 -129.13,-68.84 -61.45,43.06 C4.33,151.82 97.97,241.6 209.33,302.69 C223.86,310.66 229.18,328.9 221.21,343.42 C215.75,353.37 205.48,359 194.88,359c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_5_G" android:translateX="744.323" android:translateY="-277.96299999999997" android:pivotX="-414.08" android:pivotY="-372.985" android:rotation="28.9">
+ <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-335.95 402.99 C-351.13,402.99 -364.16,391.5 -365.76,376.07 C-367.46,359.59 -355.49,344.85 -339.01,343.14 C-162.93,324.91 -0.15,242.33 119.34,110.62 C239.66,-22.01 305.92,-193.76 305.92,-372.98 C305.92,-389.55 319.35,-402.98 335.92,-402.98 C352.49,-402.98 365.92,-389.55 365.92,-372.98 C365.92,-178.82 294.13,7.24 163.78,150.93 C34.34,293.61 -142.03,383.07 -332.83,402.82 C-333.88,402.93 -334.92,402.99 -335.95,402.99c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_2_G" android:translateX="185.385" android:translateY="70.09100000000001" android:pivotX="144.858" android:pivotY="-721.039" android:rotation="28.9" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M144.62 58.96 C144.61,58.96 144.61,58.96 144.6,58.96 C40.39,58.93 -60.82,38.66 -156.19,-1.28 C-171.48,-7.68 -178.68,-25.26 -172.28,-40.54 C-165.88,-55.82 -148.3,-63.02 -133.02,-56.62 C-45.02,-19.77 48.4,-1.07 144.63,-1.04 C161.19,-1.03 174.62,12.4 174.62,28.97 C174.61,45.53 161.18,58.96 144.62,58.96c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_0_G" android:translateX="330" android:translateY="70">
+ <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-660 -313 C-660,-313 -660,313 -660,313 C-660,313 660,313 660,313 C660,313 660,-313 660,-313 C660,-313 -660,-313 -660,-313c M300.74 -1.16 C205.46,38.62 103.22,59.09 -0.03,59.05 C-103.28,59.01 -205.51,38.48 -300.76,-1.37 C-316.05,-7.76 -323.26,-25.34 -316.86,-40.62 C-310.47,-55.91 -292.9,-63.12 -277.61,-56.72 C-189.68,-19.94 -95.32,-0.98 -0.01,-0.95 C95.3,-0.92 189.67,-19.81 277.63,-56.53 C292.92,-62.91 310.49,-55.69 316.87,-40.4 C323.25,-25.11 316.03,-7.54 300.74,-1.16c "/>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.9" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.135 0.202,0.848 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.9" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.135 0.202,0.848 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.9" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.135 0.202,0.848 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
+
diff --git a/core/res/res/drawable-w204dp/loader_horizontal_watch.xml b/core/res/res/drawable-w204dp/loader_horizontal_watch.xml
new file mode 100644
index 000000000000..fbc6eab320eb
--- /dev/null
+++ b/core/res/res/drawable-w204dp/loader_horizontal_watch.xml
@@ -0,0 +1,104 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="15dp" android:width="70dp" android:viewportHeight="15" android:viewportWidth="70">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G" android:translateX="35" android:translateY="7.5">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M35 -7.5 C35,-7.5 35,7.5 35,7.5 C35,7.5 -35,7.5 -35,7.5 C-35,7.5 -35,-7.5 -35,-7.5 C-35,-7.5 35,-7.5 35,-7.5c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="-310" android:translateY="-64" android:pivotX="345" android:pivotY="71.5" android:scaleX="0.1" android:scaleY="0.1">
+ <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-239.44799999999998" android:translateY="-341.45" android:pivotX="584.448" android:pivotY="-346.55" android:rotation="28.8" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M205.28 376.55 C200.4,376.55 195.46,375.36 190.88,372.85 C64.08,303.29 -42.54,201.07 -117.44,77.24 C-194.55,-50.25 -235.31,-196.79 -235.31,-346.55 C-235.31,-363.12 -221.88,-376.55 -205.31,-376.55 C-188.74,-376.55 -175.31,-363.12 -175.31,-346.55 C-175.31,-207.74 -137.54,-71.93 -66.1,46.19 C3.34,160.99 102.18,255.76 219.73,320.24 C234.26,328.21 239.58,346.45 231.61,360.97 C226.15,370.92 215.88,376.55 205.28,376.55c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_5_G" android:translateX="781.413" android:translateY="-295.124" android:pivotX="-436.413" android:pivotY="-392.876" android:rotation="28.8">
+ <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-353.86 422.88 C-369.04,422.88 -382.07,411.4 -383.67,395.97 C-385.37,379.49 -373.4,364.74 -356.92,363.03 C-171.06,343.79 0.76,256.62 126.89,117.59 C253.89,-22.41 323.83,-203.7 323.83,-392.88 C323.83,-409.44 337.26,-422.88 353.83,-422.88 C370.4,-422.88 383.83,-409.44 383.83,-392.88 C383.83,-188.76 308.36,6.84 171.32,157.9 C35.25,307.89 -150.15,401.94 -350.74,422.72 C-351.79,422.82 -352.83,422.88 -353.86,422.88c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_2_G" android:translateX="192.671" android:translateY="71.49599999999998" android:pivotX="152.329" android:pivotY="-759.496" android:rotation="28.8" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M152.33 60.5 C152.33,60.5 152.32,60.5 152.32,60.5 C42.76,60.47 -63.64,39.16 -163.91,-2.82 C-179.19,-9.22 -186.39,-26.8 -179.99,-42.08 C-173.59,-57.36 -156.02,-64.57 -140.73,-58.16 C-47.84,-19.27 50.77,0.47 152.34,0.5 C168.91,0.51 182.33,13.94 182.33,30.51 C182.32,47.08 168.89,60.5 152.33,60.5c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_0_G" android:translateX="345" android:translateY="71.5">
+ <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-579 -259.5 C-579,-259.5 -579,259.5 -579,259.5 C-579,259.5 579,259.5 579,259.5 C579,259.5 579,-259.5 579,-259.5 C579,-259.5 -579,-259.5 -579,-259.5c M316.17 -2.8 C216,39.02 108.52,60.54 -0.03,60.5 C-108.58,60.46 -216.04,38.87 -316.18,-3.02 C-331.47,-9.41 -338.68,-26.99 -332.28,-42.27 C-325.89,-57.56 -308.32,-64.76 -293.03,-58.37 C-200.22,-19.55 -100.61,0.46 -0.01,0.5 C100.6,0.54 200.22,-19.41 293.06,-58.17 C308.35,-64.55 325.92,-57.33 332.3,-42.04 C338.68,-26.75 331.46,-9.18 316.17,-2.8c "/>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
+
diff --git a/core/res/res/drawable-w216dp/loader_horizontal_watch.xml b/core/res/res/drawable-w216dp/loader_horizontal_watch.xml
new file mode 100644
index 000000000000..ed4b7ea0ff02
--- /dev/null
+++ b/core/res/res/drawable-w216dp/loader_horizontal_watch.xml
@@ -0,0 +1,105 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="16dp" android:width="74dp" android:viewportHeight="16" android:viewportWidth="74">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G" android:translateX="37" android:translateY="8">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M37 -8 C37,-8 37,8 37,8 C37,8 -37,8 -37,8 C-37,8 -37,-8 -37,-8 C-37,-8 37,-8 37,-8c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="-328" android:translateY="-65.5" android:pivotX="365" android:pivotY="73.5" android:scaleX="0.1" android:scaleY="0.1">
+ <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-256.447" android:translateY="-365.014" android:pivotX="621.447" android:pivotY="-368.486" android:rotation="28.8" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M218.28 398.49 C213.4,398.49 208.46,397.3 203.88,394.78 C69.34,320.99 -43.78,212.53 -123.25,81.15 C-205.06,-54.11 -248.31,-209.59 -248.31,-368.49 C-248.31,-385.05 -234.88,-398.49 -218.31,-398.49 C-201.74,-398.49 -188.31,-385.05 -188.31,-368.49 C-188.31,-220.54 -148.06,-75.8 -71.91,50.09 C2.1,172.45 107.45,273.45 232.73,342.18 C247.26,350.15 252.58,368.38 244.61,382.91 C239.15,392.86 228.88,398.49 218.28,398.49c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_5_G" android:translateX="829.0260000000001" android:translateY="-315.759" android:pivotX="-464.026" android:pivotY="-417.741" android:rotation="28.8">
+ <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-376.25 447.74 C-391.43,447.74 -404.46,436.26 -406.05,420.83 C-407.76,404.35 -395.78,389.61 -379.3,387.9 C-181.22,367.38 1.9,274.48 136.32,126.3 C271.67,-22.9 346.22,-216.12 346.22,-417.74 C346.22,-434.31 359.65,-447.74 376.22,-447.74 C392.79,-447.74 406.22,-434.31 406.22,-417.74 C406.22,-201.18 326.15,6.35 180.76,166.61 C36.39,325.75 -160.31,425.54 -373.12,447.58 C-374.17,447.69 -375.22,447.74 -376.25,447.74c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_2_G" android:translateX="203.029" android:translateY="74.06899999999996" android:pivotX="161.971" android:pivotY="-807.569" android:rotation="28.8" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M161.97 62.43 C161.97,62.43 161.96,62.43 161.96,62.43 C45.71,62.4 -67.17,39.79 -173.55,-4.75 C-188.83,-11.15 -196.03,-28.72 -189.63,-44.01 C-183.24,-59.29 -165.66,-66.49 -150.38,-60.09 C-51.37,-18.64 53.72,2.4 161.98,2.43 C178.55,2.44 191.98,15.87 191.97,32.44 C191.97,49 178.54,62.43 161.97,62.43c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_0_G" android:translateX="365" android:translateY="73.5">
+ <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-609 -244.5 C-609,-244.5 -609,244.5 -609,244.5 C-609,244.5 609,244.5 609,244.5 C609,244.5 609,-244.5 609,-244.5 C609,-244.5 -609,-244.5 -609,-244.5c M335.44 -4.16 C229.17,40.21 115.13,63.04 -0.04,63 C-115.21,62.96 -229.22,40.05 -335.47,-4.39 C-350.76,-10.79 -357.95,-28.36 -351.56,-43.65 C-345.17,-58.93 -327.59,-66.14 -312.31,-59.74 C-213.39,-18.36 -107.24,2.96 -0.02,3 C107.21,3.04 213.38,-18.22 312.33,-59.53 C327.62,-65.91 345.19,-58.69 351.57,-43.4 C357.95,-28.11 350.73,-10.54 335.44,-4.16c "/>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.3" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.3" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.8" android:valueTo="-51.3" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
+
+
diff --git a/core/res/res/drawable-w228dp/loader_horizontal_watch.xml b/core/res/res/drawable-w228dp/loader_horizontal_watch.xml
new file mode 100644
index 000000000000..6b86c634d554
--- /dev/null
+++ b/core/res/res/drawable-w228dp/loader_horizontal_watch.xml
@@ -0,0 +1,103 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="14dp" android:width="76dp" android:viewportHeight="14" android:viewportWidth="76">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G" android:translateX="39" android:translateY="8">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M39 -8 C39,-8 39,8 39,8 C39,8 -39,8 -39,8 C-39,8 -39,-8 -39,-8 C-39,-8 39,-8 39,-8c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="-345" android:translateY="-67" android:pivotX="384" android:pivotY="75" android:scaleX="0.1" android:scaleY="0.1">
+ <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-274.19" android:translateY="-390.077" android:pivotX="658.448" android:pivotY="-390.423" android:rotation="28.7" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M231.28 420.42 C226.4,420.42 221.45,419.23 216.88,416.72 C74.61,338.68 -45.02,224 -129.06,85.06 C-171.54,14.82 -204.38,-60.73 -226.66,-139.5 C-249.65,-220.76 -261.31,-305.18 -261.31,-390.42 C-261.31,-406.99 -247.88,-420.42 -231.31,-420.42 C-214.74,-420.42 -201.31,-406.99 -201.31,-390.42 C-201.31,-310.71 -190.42,-231.78 -168.93,-155.83 C-148.11,-82.23 -117.42,-11.63 -77.72,54 C0.86,183.92 112.71,291.15 245.73,364.12 C260.26,372.08 265.58,390.32 257.61,404.85 C252.15,414.79 241.88,420.42 231.28,420.42c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_5_G" android:translateX="875.8979999999999" android:translateY="-337.894" android:pivotX="-491.64" android:pivotY="-442.606" android:rotation="28.7">
+ <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-398.64 472.61 C-413.82,472.61 -426.84,461.13 -428.44,445.7 C-430.15,429.22 -418.17,414.47 -401.69,412.77 C-191.38,390.98 3.04,292.33 145.75,135.01 C289.46,-23.4 368.6,-228.54 368.6,-442.61 C368.6,-459.17 382.04,-472.61 398.6,-472.61 C415.17,-472.61 428.6,-459.17 428.6,-442.61 C428.6,-213.6 343.93,5.85 190.19,175.33 C37.53,343.61 -170.48,449.13 -395.51,472.44 C-396.56,472.55 -397.6,472.61 -398.64,472.61c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_2_G" android:translateX="212.64499999999998" android:translateY="75.14200000000005" android:pivotX="171.613" android:pivotY="-855.642" android:rotation="28.7" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M171.61 64.36 C171.61,64.36 171.61,64.36 171.61,64.36 C48.68,64.32 -70.7,40.42 -183.19,-6.68 C-198.47,-13.07 -205.68,-30.65 -199.28,-45.93 C-192.88,-61.22 -175.3,-68.42 -160.02,-62.02 C-54.9,-18.01 56.68,4.33 171.62,4.36 C188.19,4.36 201.62,17.8 201.61,34.36 C201.61,50.93 188.18,64.36 171.61,64.36c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_0_G" android:translateX="384" android:translateY="75">
+ <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-611 -259 C-611,-259 -611,259 -611,259 C-611,259 611,259 611,259 C611,259 611,-259 611,-259 C611,-259 -611,-259 -611,-259c M354.66 -6.52 C242.36,40.4 121.76,64.54 -0.04,64.5 C-121.84,64.46 -242.44,40.23 -354.74,-6.76 C-370.04,-13.16 -377.24,-30.73 -370.84,-46.02 C-364.44,-61.3 -346.94,-68.51 -331.64,-62.12 C-226.54,-18.18 -113.84,4.46 -0.04,4.5 C113.76,4.54 226.56,-18.02 331.56,-61.89 C346.86,-68.27 364.46,-61.05 370.86,-45.76 C377.26,-30.47 369.96,-12.9 354.66,-6.52c "/>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/core/res/res/drawable-w240dp/loader_horizontal_watch.xml b/core/res/res/drawable-w240dp/loader_horizontal_watch.xml
new file mode 100644
index 000000000000..ad60bbdc420c
--- /dev/null
+++ b/core/res/res/drawable-w240dp/loader_horizontal_watch.xml
@@ -0,0 +1,104 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="17dp" android:width="82dp" android:viewportHeight="17" android:viewportWidth="82">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G" android:translateX="41" android:translateY="8.5">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M41 -8.5 C41,-8.5 41,8.5 41,8.5 C41,8.5 -41,8.5 -41,8.5 C-41,8.5 -41,-8.5 -41,-8.5 C-41,-8.5 41,-8.5 41,-8.5c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="-362.5" android:translateY="-69" android:pivotX="403.5" android:pivotY="77.5" android:scaleX="0.1" android:scaleY="0.1">
+ <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-291.64799999999997" android:translateY="-414.141" android:pivotX="695.448" android:pivotY="-412.359" android:rotation="28.7" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M244.28 442.36 C239.4,442.36 234.45,441.17 229.88,438.66 C79.87,356.38 -46.26,235.46 -134.87,88.96 C-179.66,14.91 -214.28,-64.74 -237.78,-147.79 C-262.02,-233.47 -274.31,-322.49 -274.31,-412.36 C-274.31,-428.93 -260.88,-442.36 -244.31,-442.36 C-227.74,-442.36 -214.31,-428.93 -214.31,-412.36 C-214.31,-328.01 -202.78,-244.49 -180.05,-164.12 C-158.01,-86.24 -125.54,-11.54 -83.53,57.91 C-0.38,195.38 117.97,308.85 258.73,386.05 C273.26,394.02 278.58,412.26 270.61,426.78 C265.15,436.73 254.88,442.36 244.28,442.36c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_5_G" android:translateX="923.0530000000001" android:translateY="-359.029" android:pivotX="-519.253" android:pivotY="-467.471" android:rotation="28.7">
+ <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-421.02 497.47 C-436.2,497.47 -449.23,485.99 -450.83,470.56 C-452.53,454.08 -440.56,439.34 -424.08,437.63 C-201.54,414.57 4.18,310.19 155.19,143.73 C229.54,61.77 287.7,-31.75 328.04,-134.22 C369.81,-240.3 390.99,-352.42 390.99,-467.47 C390.99,-484.04 404.42,-497.47 420.99,-497.47 C437.56,-497.47 450.99,-484.04 450.99,-467.47 C450.99,-226.02 361.72,5.35 199.63,184.04 C38.67,361.47 -180.63,472.73 -417.89,497.31 C-418.94,497.42 -419.99,497.47 -421.02,497.47c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_2_G" android:translateX="222.54600000000002" android:translateY="77.21400000000006" android:pivotX="181.254" android:pivotY="-903.714" android:rotation="28.7" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M181.26 66.28 C181.25,66.28 181.25,66.28 181.25,66.28 C51.64,66.25 -74.22,41.06 -192.83,-8.6 C-208.12,-15 -215.32,-32.58 -208.92,-47.86 C-202.52,-63.15 -184.94,-70.35 -169.66,-63.95 C-58.42,-17.38 59.64,6.25 181.26,6.28 C197.83,6.29 211.26,19.72 211.26,36.29 C211.25,52.86 197.82,66.28 181.26,66.28c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_0_G" android:translateX="403.5" android:translateY="77.5">
+ <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-630.5 -255.5 C-630.5,-255.5 -630.5,255.5 -630.5,255.5 C-630.5,255.5 630.5,255.5 630.5,255.5 C630.5,255.5 630.5,-255.5 630.5,-255.5 C630.5,-255.5 -630.5,-255.5 -630.5,-255.5c M374 -8.88 C255.5,40.59 128.4,66.04 0,66 C-128.4,65.95 -255.6,40.42 -374,-9.14 C-389.3,-15.53 -396.5,-33.11 -390.1,-48.39 C-383.7,-63.68 -366.2,-70.88 -350.9,-64.49 C-239.7,-18 -120.5,5.96 0,6 C120.4,6.04 239.7,-17.84 350.9,-64.25 C366.2,-70.63 383.7,-63.41 390.1,-48.12 C396.5,-32.83 389.3,-15.26 374,-8.88c "/>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
+
diff --git a/core/res/res/drawable/ic_notification_summarization.xml b/core/res/res/drawable/ic_notification_summarization.xml
index de905fa10728..d476872a0e20 100644
--- a/core/res/res/drawable/ic_notification_summarization.xml
+++ b/core/res/res/drawable/ic_notification_summarization.xml
@@ -19,5 +19,6 @@ Copyright (C) 2025 The Android Open Source Project
android:tint="?android:attr/colorControlNormal"
android:viewportHeight="960"
android:viewportWidth="960">
- <path android:fillColor="#ffffff" android:pathData="M354,673L480,597L606,674L573,530L684,434L538,421L480,285L422,420L276,433L387,530L354,673ZM233,840L298,559L80,370L368,345L480,80L592,345L880,370L662,559L727,840L480,691L233,840ZM480,490L480,490L480,490L480,490L480,490L480,490L480,490L480,490L480,490L480,490Z"/>
+ <path android:fillColor="#ffffff"
+ android:pathData="M120,840L120,760L600,760L600,840L120,840ZM120,640L120,560L840,560L840,640L120,640ZM120,440L120,360L560,360L560,440L120,440ZM700,480Q700,388 636,324Q572,260 480,260Q572,260 636,196Q700,132 700,40Q700,132 764,196Q828,260 920,260Q828,260 764,324Q700,388 700,480Z"/>
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/loader_horizontal_watch.xml b/core/res/res/drawable/loader_horizontal_watch.xml
new file mode 100644
index 000000000000..6b86c634d554
--- /dev/null
+++ b/core/res/res/drawable/loader_horizontal_watch.xml
@@ -0,0 +1,103 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="14dp" android:width="76dp" android:viewportHeight="14" android:viewportWidth="76">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G" android:translateX="39" android:translateY="8">
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M39 -8 C39,-8 39,8 39,8 C39,8 -39,8 -39,8 C-39,8 -39,-8 -39,-8 C-39,-8 39,-8 39,-8c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="-345" android:translateY="-67" android:pivotX="384" android:pivotY="75" android:scaleX="0.1" android:scaleY="0.1">
+ <group android:name="_R_G_L_0_G_L_6_G" android:translateX="-274.19" android:translateY="-390.077" android:pivotX="658.448" android:pivotY="-390.423" android:rotation="28.7" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_6_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M231.28 420.42 C226.4,420.42 221.45,419.23 216.88,416.72 C74.61,338.68 -45.02,224 -129.06,85.06 C-171.54,14.82 -204.38,-60.73 -226.66,-139.5 C-249.65,-220.76 -261.31,-305.18 -261.31,-390.42 C-261.31,-406.99 -247.88,-420.42 -231.31,-420.42 C-214.74,-420.42 -201.31,-406.99 -201.31,-390.42 C-201.31,-310.71 -190.42,-231.78 -168.93,-155.83 C-148.11,-82.23 -117.42,-11.63 -77.72,54 C0.86,183.92 112.71,291.15 245.73,364.12 C260.26,372.08 265.58,390.32 257.61,404.85 C252.15,414.79 241.88,420.42 231.28,420.42c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_5_G" android:translateX="875.8979999999999" android:translateY="-337.894" android:pivotX="-491.64" android:pivotY="-442.606" android:rotation="28.7">
+ <path android:name="_R_G_L_0_G_L_5_G_D_0_P_0" android:fillColor="#303030" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-398.64 472.61 C-413.82,472.61 -426.84,461.13 -428.44,445.7 C-430.15,429.22 -418.17,414.47 -401.69,412.77 C-191.38,390.98 3.04,292.33 145.75,135.01 C289.46,-23.4 368.6,-228.54 368.6,-442.61 C368.6,-459.17 382.04,-472.61 398.6,-472.61 C415.17,-472.61 428.6,-459.17 428.6,-442.61 C428.6,-213.6 343.93,5.85 190.19,175.33 C37.53,343.61 -170.48,449.13 -395.51,472.44 C-396.56,472.55 -397.6,472.61 -398.64,472.61c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_2_G" android:translateX="212.64499999999998" android:translateY="75.14200000000005" android:pivotX="171.613" android:pivotY="-855.642" android:rotation="28.7" android:scaleY="0">
+ <path android:name="_R_G_L_0_G_L_2_G_D_0_P_0" android:fillColor="#ffffff" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M171.61 64.36 C171.61,64.36 171.61,64.36 171.61,64.36 C48.68,64.32 -70.7,40.42 -183.19,-6.68 C-198.47,-13.07 -205.68,-30.65 -199.28,-45.93 C-192.88,-61.22 -175.3,-68.42 -160.02,-62.02 C-54.9,-18.01 56.68,4.33 171.62,4.36 C188.19,4.36 201.62,17.8 201.61,34.36 C201.61,50.93 188.18,64.36 171.61,64.36c "/>
+ </group>
+ <group android:name="_R_G_L_0_G_L_0_G" android:translateX="384" android:translateY="75">
+ <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-611 -259 C-611,-259 -611,259 -611,259 C-611,259 611,259 611,259 C611,259 611,-259 611,-259 C611,-259 -611,-259 -611,-259c M354.66 -6.52 C242.36,40.4 121.76,64.54 -0.04,64.5 C-121.84,64.46 -242.44,40.23 -354.74,-6.76 C-370.04,-13.16 -377.24,-30.73 -370.84,-46.02 C-364.44,-61.3 -346.94,-68.51 -331.64,-62.12 C-226.54,-18.18 -113.84,4.46 -0.04,4.5 C113.76,4.54 226.56,-18.02 331.56,-61.89 C346.86,-68.27 364.46,-61.05 370.86,-45.76 C377.26,-30.47 369.96,-12.9 354.66,-6.52c "/>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_6_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="333" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_5_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="rotation" android:duration="983" android:startOffset="0" android:valueFrom="28.7" android:valueTo="-51.4" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.402,0.136 0.202,0.847 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="scaleY" android:duration="0" android:startOffset="133" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:repeatCount="infinite" android:propertyName="translateX" android:duration="1000" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/core/res/res/layout/notification_2025_conversation_header.xml b/core/res/res/layout/notification_2025_conversation_header.xml
index 75bd244cbbf4..1bde17358825 100644
--- a/core/res/res/layout/notification_2025_conversation_header.xml
+++ b/core/res/res/layout/notification_2025_conversation_header.xml
@@ -29,7 +29,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- android:textSize="@dimen/notification_2025_title_text_size"
+ android:textSize="16sp"
android:singleLine="true"
android:layout_weight="1"
/>
diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml
index 054583297d37..d29b7af9e24e 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_base.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml
@@ -102,7 +102,6 @@
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- android:textSize="@dimen/notification_2025_title_text_size"
/>
<include layout="@layout/notification_2025_top_line_views" />
diff --git a/core/res/res/layout/notification_2025_template_collapsed_media.xml b/core/res/res/layout/notification_2025_template_collapsed_media.xml
index 9959b666b3bf..5beab508aecf 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_media.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_media.xml
@@ -104,7 +104,6 @@
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- android:textSize="@dimen/notification_2025_title_text_size"
/>
<include layout="@layout/notification_2025_top_line_views" />
diff --git a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
index 85ca124de8ff..d7c3263904d4 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
@@ -130,7 +130,6 @@
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- android:textSize="@dimen/notification_2025_title_text_size"
/>
<include layout="@layout/notification_2025_top_line_views" />
diff --git a/core/res/res/layout/notification_2025_template_compact_heads_up_base.xml b/core/res/res/layout/notification_2025_template_compact_heads_up_base.xml
index 11fc48668ad7..52bc7b8ea3bb 100644
--- a/core/res/res/layout/notification_2025_template_compact_heads_up_base.xml
+++ b/core/res/res/layout/notification_2025_template_compact_heads_up_base.xml
@@ -69,7 +69,6 @@
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- android:textSize="@dimen/notification_2025_title_text_size"
/>
<include layout="@layout/notification_2025_top_line_views" />
</NotificationTopLineView>
diff --git a/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml b/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml
index bf70a5eff47e..cf9ff6bef6f8 100644
--- a/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml
+++ b/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml
@@ -90,7 +90,6 @@
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- android:textSize="@dimen/notification_2025_title_text_size"
/>
<include layout="@layout/notification_2025_top_line_views" />
</NotificationTopLineView>
diff --git a/core/res/res/layout/notification_2025_template_header.xml b/core/res/res/layout/notification_2025_template_header.xml
index 72b3798e0780..5aae67802af9 100644
--- a/core/res/res/layout/notification_2025_template_header.xml
+++ b/core/res/res/layout/notification_2025_template_header.xml
@@ -59,7 +59,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
- android:layout_toStartOf="@id/expand_button"
+ android:layout_toStartOf="@id/expand_button_container"
android:layout_alignWithParentIfMissing="true"
android:layout_marginVertical="@dimen/notification_2025_margin"
android:clipChildren="false"
@@ -81,12 +81,30 @@
android:focusable="false"
/>
- <include layout="@layout/notification_2025_expand_button"
+
+ <LinearLayout
+ android:id="@+id/expand_button_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="top|end"
- android:layout_alignParentEnd="true" />
+ android:layout_alignParentEnd="true"
+ android:orientation="vertical"
+ >
+ <FrameLayout
+ android:id="@+id/expand_button_spacer"
+ android:layout_width="@dimen/notification_2025_expand_button_pill_width"
+ android:layout_height="@dimen/notification_2025_expand_button_pill_height"
+ android:layout_centerVertical="true"
+ android:layout_alignParentEnd="true"
+ android:layout_margin="@dimen/notification_2025_margin"
+ android:visibility="gone" />
+
+ <include layout="@layout/notification_2025_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|end"
+ android:layout_alignParentEnd="true" />
+ </LinearLayout>
<include layout="@layout/notification_close_button"
android:id="@+id/close_button"
android:layout_width="@dimen/notification_close_button_size"
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 57959361bd48..b7fd737a4e39 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -62,7 +62,7 @@
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
- android:layout_toStartOf="@id/expand_button"
+ android:layout_toStartOf="@id/expand_button_container"
android:layout_alignWithParentIfMissing="true"
android:clipChildren="false"
android:gravity="center_vertical"
@@ -83,12 +83,28 @@
android:focusable="false"
/>
- <include layout="@layout/notification_expand_button"
+ <LinearLayout
+ android:id="@+id/expand_button_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentEnd="true" />
+ android:layout_alignParentEnd="true"
+ android:orientation="vertical"
+ >
+ <FrameLayout
+ android:id="@+id/expand_button_spacer"
+ android:layout_width="@dimen/notification_expand_button_pill_height"
+ android:layout_height="@dimen/notification_header_height"
+ android:layout_centerVertical="true"
+ android:layout_alignParentEnd="true"
+ android:layout_marginHorizontal="16dp"
+ android:visibility="gone" />
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentEnd="true" />
+ </LinearLayout>
<include layout="@layout/notification_close_button"
android:id="@+id/close_button"
android:layout_width="@dimen/notification_close_button_size"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 368cf65ae67c..5da0924c08c3 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Ontspeld"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Ontspeld <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Appinligting"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Direktedelingteikens"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Appvoorstelle"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Applys"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Begin tans demonstrasie …"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Stel toestel tans terug …"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-paneel links"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-paneel regs"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-paneel middel"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Outoklik-tipe instellingspaneel"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Linksklik"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Onderbreek"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posisie"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"het \'n prent gestuur"</string>
@@ -2269,7 +2270,7 @@
<string name="resolver_cross_profile_blocked" msgid="3014597376026044840">"Deur jou IT-admin geblokkeer"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Hierdie inhoud kan nie met werkprogramme gedeel word nie"</string>
<string name="resolver_cant_access_work_apps_explanation" msgid="1129960195389373279">"Hierdie inhoud kan nie met werkprogramme oopgemaak word nie"</string>
- <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Hierdie inhoud kan nie met persoonlike programme gedeel word nie"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Hierdie inhoud kan nie met persoonlike apps gedeel word nie"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Hierdie inhoud kan nie met persoonlike programme oopgemaak word nie"</string>
<string name="resolver_turn_on_work_apps" msgid="1535946298236678122">"Werkapps is onderbreek"</string>
<string name="resolver_switch_on_work" msgid="4527096360772311894">"Hervat"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Apps"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Jou vingerafdrukke kan nie meer herken word nie. Stel Vingerafdrukslot weer op."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-toestel is ingeprop wanneer dit gesluit is"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-toestel is ingeprop wanneer jou Android gesluit is. Om die toestel te gebruik, moet jy eers jou Android ontsluit en dan weer die USB-toestel insit om dit te gebruik."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Verdagte USB-aktiwiteit"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB-datasein is gedeaktiveer."</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 1ab3beb71858..c55f1c63bf04 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"ንቀል"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> ንቀል"</string>
<string name="app_info" msgid="6113278084877079851">"የመተግበሪያ መረጃ"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"የቀጥታ ማጋራት ዒላማዎች"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"የመተግበሪያ አስተያየቶች"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"የመተግበሪያ ዝርዝር"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ማሳያን በማስጀመር ላይ…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"መሣሪያን ዳግም በማስጀመር ላይ…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ከDpad በስተግራ"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ከDpad በስተቀኝ"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"የDpad ማዕከል"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"የራስ-ሰር ጠቅ ማድረግ ትየባ ቅንብሮች ፓነል"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"የግራ ጠቅታ"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ባለበት አቁም"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"አቀማመጥ"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>፦"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"አንድ ምስል ልከዋል"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"ካርታዎች"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"መተግበሪያዎች"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"ከእንግዲህ የጣት አሻራዎችዎ ሊለዩ አይችሉም። በጣት አሻራ መክፈቻን እንደገና ያዋቅሩ።"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"ሲቆለፍ የUSB መሣሪያ ተሰክቷል።"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android ሲቆለፍ የUSB መሣሪያ ተሰክቷል። መሣሪያ ለመጠቀም እባክዎ መጀመሪያ Androidን ይክፈቱ እና ከዚያም እሱን ለመጠቀም የUSB መሣሪያ እንደገና ያስገቡ።"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"አጠራጣሪ የUSB እንቅስቃሴ"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"የUSB የውሂብ ምልክት ተሰናክሏል።"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 637b08daa171..f542d439bf2e 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1468,7 +1468,7 @@
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"انقر لاختيار لغة وتنسيق"</string>
<string name="fast_scroll_alphabet" msgid="8854435958703888376">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</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>
@@ -2092,12 +2092,9 @@
<string name="unpin_target" msgid="3963318576590204447">"إزالة تثبيت"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"إزالة تثبيت <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"معلومات عن التطبيق"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"أهداف المشاركة المباشرة"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"التطبيقات المقترَحة"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"قائمة التطبيقات"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"جارٍ بدء العرض التوضيحي…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"جارٍ إعادة ضبط الجهاز…"</string>
@@ -2254,6 +2251,14 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"الزرّ المركزي"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"لوحة إعدادات نوع النقر التلقائي"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"النقر بالزر الأيسر"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
+ <skip />
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"إيقاف مؤقت"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"تعديل الموضع"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string>
@@ -2530,12 +2535,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"‏خرائط Google"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"التطبيقات"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"لم يعد بالإمكان التعرّف على بصمات أصابعك. يجب ضبط ميزة \"فتح الجهاز ببصمة الإصبع\" مجددًا."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"‏تم توصيل جهاز USB عندما كان الجهاز مقفلاً"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"‏تم توصيل جهاز USB عندما كان جهاز Android مقفلاً. لاستخدام الجهاز، يُرجى فتح قفل جهاز Android أولاً ثم إعادة إدخال جهاز USB لاستخدامه."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"‏نشاط مريب في جهاز USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"‏تم إيقاف مؤشر بيانات USB."</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 95d442bf43a4..b8afd2edc2e1 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"আনপিন"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g>ক আনপিন কৰক"</string>
<string name="app_info" msgid="6113278084877079851">"এপ্ সম্পৰ্কীয় তথ্য"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"পোনপটীয়াকৈ কৰা শ্বেয়াৰৰ লক্ষ্য"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"এপৰ পৰামৰ্শ"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"এপৰ সূচী"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ডেম\' আৰম্ভ কৰি থকা হৈছে…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"ডিভাইচটো আকৌ ছেটিং কৰি থকা হৈছে…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ডিপেডৰ বাওঁফালৰ বুটাম"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ডিপেডৰ সোঁফালৰ বুটাম"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ডিপেডৰ মাজৰ বুটাম"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"প্ৰকাৰৰ ছেটিঙৰ পেনেলত স্বয়ংক্ৰিয়ভাৱে ক্লিক কৰক"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"বাওঁফালৰ ক্লিক"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"পজ কৰক"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"স্থান"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"মেপ"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"এপ্লিকেশ্বন"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"আপোনাৰ ফিংগাৰপ্ৰিণ্ট আৰু চিনাক্ত কৰিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট আনলক পুনৰ ছেট আপ কৰক।"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"লক হৈ থাকোঁতে USB ডিভাইচ প্লাগ ইন কৰা হৈছে"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android লক হৈ থাকোঁতে USB ডিভাইচ প্লাগ ইন কৰা হৈছে। ডিভাইচ ব্যৱহাৰ কৰিবলৈ অনুগ্ৰহ কৰি প্ৰথমে Android আনলক কৰক আৰু তাৰ পাছত USB ডিভাইচটো ব্যৱহাৰ কৰিবলৈ সেইটো পুনৰ ভৰাওক।"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"সন্দেহজনক USBৰ কাৰ্যকলাপ"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB ডেটা ছিগনেল অক্ষম কৰা হৈছে।"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 4f7da4f74a71..affa56954001 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Çıxarın"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"İşarələməyin: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Tətbiq haqqında"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Birbaşa paylaşım hədəfləri"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Tətbiq təklifləri"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Tətbiq siyahısı"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demo başlayır…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Cihaz sıfırlanır…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Sola"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Sağa"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Mərkəzə"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Avtomatik klikləmə növü üzrə ayarlar paneli"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Sola klik"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Durdurun"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Mövqe"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"şəkil göndərdi"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Xəritə"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Tətbiqlər"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Barmaq izlərinizi artıq tanımaq mümkün deyil. Barmaqla Kilidaçmanı yenidən ayarlayın."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Kilidli olduqda USB cihazı qoşulu olur"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android kilidləndikdə USB cihazı qoşulu olur. Cihazdan istifadə etmək üçün əvvəlcə Android-i kiliddən çıxarın və sonra USB cihazını yenidən taxaraq ondan istifadə edin."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Şübhəli USB fəaliyyəti"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB data siqnalı deaktiv edilib."</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 049359b85a1e..3acc8df73a83 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Otkači"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Otkači aplikaciju <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informacije o aplikaciji"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Ciljevi direktnog deljenja"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Predlozi aplikacija"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista aplikacija"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Pokrećemo demonstraciju..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Resetujemo uređaj..."</string>
@@ -2251,6 +2248,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"centar na D-pad-u"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Okno sa podešavanjima tipa automatskog klika"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Levi klik"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Kliknite desnim tasterom"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dvaput kliknite"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Prevucite"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Skrolujte"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauziraj"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicija"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string>
@@ -2527,12 +2528,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Mape"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikacije"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Otisci prstiju više ne mogu da se prepoznaju. Ponovo podesite otključavanje otiskom prsta."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB uređaj je priključen kada je Android zaključan"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB uređaj je priključen kada je Android zaključan. Da biste koristili uređaj, prvo otključajte Android, pa ponovo ubacite USB uređaj da biste ga koristili."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Sumnjiva USB aktivnost"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Signal za prenos podataka sa USB-a je onemogućen."</string>
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 02cc889e9ecc..7c827bbecaab 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2090,12 +2090,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Адмацаваць"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Адмацаваць праграму \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string>
<string name="app_info" msgid="6113278084877079851">"Звесткі аб праграме"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Адрасаты для прамога абагульвання"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Прапановы праграм"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Спіс праграм"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Ідзе запуск дэманстрацыі…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Ідзе скід налад прылады…"</string>
@@ -2250,14 +2247,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Улева на панэлі кіравання"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Управа на панэлі кіравання"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"У цэнтр на панэлі кіравання"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Панэль налад тыпу аўтаматычнага націскання"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Націсканне левай клавішай мышы"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Націсканне правай кнопкай мышы"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Двайное націсканне"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Перацягванне"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Гартанне"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Прыпыніць"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Пазіцыя"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"адпраўлены відарыс"</string>
@@ -2532,12 +2529,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Карты"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Праграмы"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Вашы адбіткі пальцаў больш не распазнаюцца. Паўторна наладзьце разблакіроўку адбіткам пальца."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-прылада падключана, калі прылада заблакіравана"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-прылада падключана, калі прылада Android заблакіравана. Каб выкарыстоўваць прыладу, разблакіруйце прыладу Android і паўторна ўстаўце USB-прыладу."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Падазроная актыўнасць на USB-прыладзе"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Сігнал даных USB адключаны."</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d85e319edaaa..c3a271267a36 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Освобождаване"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Премахване на фиксирането на <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Информация за приложението"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Цели за директно споделяне"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Предложения за приложения"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Списък с приложения"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Демонстрацията се стартира…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Устройството се нулира…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Контролен пад – ляво"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Контролен пад – дясно"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Контролен пад – център"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Панел с настройки за типа на автоматичното кликване"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Кликване с ляв бутон"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Пауза"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Позиция"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"изпратено изображение"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Карти"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Приложения"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Отпечатъците ви вече не могат да бъдат разпознати. Настройте отново „Отключване с отпечатък“."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB устройството е свързано, когато устройството е заключено"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB устройството е включено, когато устройството с Android е заключено. За да използвате устройството, първо отключете Android и след това поставете отново USB устройството."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Подозрителна активност на USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Сигналът за данни през USB е деактивиран."</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 19d4962175b1..f6492c5b9ef3 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"আনপিন করুন"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> অ্যাপ আনপিন করুন"</string>
<string name="app_info" msgid="6113278084877079851">"অ্যাপের তথ্য"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"সরাসরি টার্গেট শেয়ার করুন"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"অ্যাপ সাজেশন"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"অ্যাপ তালিকা"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ডেমো শুরু করা হচ্ছে…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"ডিভাইস আবার সেট করা হচ্ছে…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ডিপ্যাড (Dpad)-এর বাঁদিকে"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ডিপ্যাড (Dpad)-এর ডানদিকে"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ডিপ্যাড (Dpad)-এর মাঝখানে"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"অটোক্লিক টাইপ সেটিংস প্যানেল"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"বাঁদিকের বোতামে ক্লিক করুন"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"পজ করুন"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"পজিশন"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"একটি ছবি পাঠানো হয়েছে"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"ম্যাপ"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"অ্যাপ্লিকেশন"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"আপনার ফিঙ্গারপ্রিন্ট আর শনাক্ত করা যাবে না। \'ফিঙ্গারপ্রিন্ট আনলক\' ফিচার আবার সেট-আপ করুন।"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"লক থাকাকালীন USB ডিভাইস প্লাগ-ইন করা হয়েছে"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android লক থাকাকালীন USB ডিভাইস প্লাগ-ইন করা হয়েছে। ডিভাইস ব্যবহার করতে, প্রথমে Android আনলক করুন এবং তারপর সেটি ব্যবহার করতে USB ডিভাইস আবার যোগ করুন।"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"সন্দেহজনক USB অ্যাক্টিভিটি"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB ডেটা সিগন্যাল বন্ধ করা হয়েছে।"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index e95bedf3dcd3..3ff85acf48a0 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Otkači"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Otkači aplikaciju <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informacije o aplikaciji"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Ciljevi direktnog dijeljenja"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Prijedlozi aplikacija"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista aplikacija"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Pokretanje demonstracije…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Vraćanje uređaja na početne postavke…"</string>
@@ -2251,8 +2248,12 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Upravljač sredina"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Ploča postavki vrste automatskog klika"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Lijevi klik"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Desni klik"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dvostruki klik"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Povuci"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Pomakni se"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauziraj"</string>
- <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicija"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Položaj"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslao/la sliku"</string>
@@ -2266,7 +2267,7 @@
<string name="resolver_cross_profile_blocked" msgid="3014597376026044840">"Blokirao je vaš IT administrator"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Ovaj sadržaj nije moguće dijeliti pomoću poslovnih aplikacija"</string>
<string name="resolver_cant_access_work_apps_explanation" msgid="1129960195389373279">"Ovaj sadržaj nije moguće otvoriti pomoću poslovnih aplikacija"</string>
- <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Ovaj sadržaj nije moguće dijeliti pomoću ličnih aplikacija"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Ovaj sadržaj nije moguće dijeliti s ličnim aplikacijama"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Ovaj sadržaj nije moguće otvoriti pomoću ličnih aplikacija"</string>
<string name="resolver_turn_on_work_apps" msgid="1535946298236678122">"Poslovne aplikacije su pauzirane"</string>
<string name="resolver_switch_on_work" msgid="4527096360772311894">"Ponovo pokreni"</string>
@@ -2527,12 +2528,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Mape"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikacije"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Vaši otisci prstiju se više ne mogu prepoznavati. Ponovo postavite otključavanje otiskom prsta."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB uređaj je priključen dok je uređaj bio zaključan"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB uređaj je priključen dok je Android bio zaključan. Da koristite uređaj, prvo otključajte Android, a zatim ponovo umetnite USB uređaj da ga koristite."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Sumnjiva aktivnost USB-a"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Podatkovni signal USB-a je onemogućen."</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 9b67f28bbfb2..9b61887da0bd 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"No fixis"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"No fixis <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informació de l\'app"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Destinataris de la compartició directa"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Suggeriments d\'aplicacions"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Llista d\'aplicacions"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"S\'està iniciant la demostració…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"S\'està restablint el dispositiu…"</string>
@@ -2249,14 +2246,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Creu direccional: esquerra"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Creu direccional: dreta"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Creu direccional: centre"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Tauler de configuració del tipus de clic automàtic"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic esquerre"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Posa en pausa"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posició"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha enviat una imatge"</string>
@@ -2531,12 +2532,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplicacions"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Les teves empremtes digitals ja no es poden reconèixer. Torna a configurar Desbloqueig amb empremta digital."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"S\'ha connectat un dispositiu USB quan el dispositiu estava bloquejat"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"El dispositiu USB està connectat quan Android està bloquejat. Per utilitzar el dispositiu, primer desbloqueja Android i, a continuació, torna a inserir el dispositiu USB per utilitzar-lo."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Activitat USB sospitosa"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"El senyal de dades per USB s\'ha desactivat."</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f4eef972c0d1..9c8cc9a17878 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2252,6 +2252,14 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad střed"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel nastavení typu automatického kliknutí"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Kliknutí levým"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
+ <skip />
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pozastavit"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozice"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index bcdb691eaf86..1b96dbbe07f7 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Frigør"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Frigør <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Appinfo"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Personer/grupper, der skal deles direkte med"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Appforslag"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Appliste"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Starter demoen…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Nulstiller enheden…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad, venstre"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad, højre"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad, midten"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel med indstillinger for type af automatisk klik"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Venstreklik"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Sæt på pause"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Placering"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sendte et billede"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Kort"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Apps"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Dine fingeraftryk kan ikke længere genkendes. Konfigurer fingeroplåsning igen."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-enheden er tilsluttet, når Android er låst"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-enheden er tilsluttet, når Android er låst. Hvis du vil bruge enheden, skal du først låse Android op og derefter tilslutte USB-enheden."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Mistænkelig USB-aktivitet"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB-datasignalet er blevet deaktiveret."</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4191512fd018..73e7b9a9c0c8 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2042,7 +2042,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"App nicht verfügbar"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ist momentan nicht verfügbar. Dies wird über die App \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\" verwaltet."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Weitere Informationen"</string>
- <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"App-Pausierung aufheben"</string>
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Pausierung der App aufheben"</string>
<string name="work_mode_off_title" msgid="6367463960165135829">"Geschäftliche Apps nicht mehr pausieren?"</string>
<string name="work_mode_turn_on" msgid="5316648862401307800">"Nicht mehr pausieren"</string>
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Notruf"</string>
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Markierung entfernen"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> loslösen"</string>
<string name="app_info" msgid="6113278084877079851">"App-Informationen"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"„Direct Share“-Ziele"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"App-Vorschläge"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"App-Liste"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demo wird gestartet…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Gerät wird zurückgesetzt…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Steuerkreuz nach links"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Steuerkreuz nach rechts"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Steuerkreuz Mitte"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Bereich mit Einstellungen für automatische Klicks"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Linksklick"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausieren"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"hat ein Bild gesendet"</string>
@@ -2267,9 +2268,9 @@
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Private Ansicht"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Geschäftliche Ansicht"</string>
<string name="resolver_cross_profile_blocked" msgid="3014597376026044840">"Von deinem IT-Administrator blockiert"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Diese Art von Inhalt kann nicht über geschäftliche Apps geteilt werden"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Dieser Inhalt kann nicht über geschäftliche Apps geteilt werden"</string>
<string name="resolver_cant_access_work_apps_explanation" msgid="1129960195389373279">"Diese Art von Inhalt kann nicht mit geschäftlichen Apps geöffnet werden"</string>
- <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Diese Art von Inhalt kann nicht über private Apps geteilt werden"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Dieser Inhalt kann nicht über private Apps geteilt werden"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"Diese Art von Inhalt kann nicht mit privaten Apps geöffnet werden"</string>
<string name="resolver_turn_on_work_apps" msgid="1535946298236678122">"Geschäftliche Apps sind pausiert"</string>
<string name="resolver_switch_on_work" msgid="4527096360772311894">"Nicht mehr pausieren"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Anwendungen"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Deine Fingerabdrücke können nicht mehr erkannt werden. Bitte richte die Entsperrung per Fingerabdruck neu ein."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-Gerät wurde angeschlossen, als das Android-Gerät gesperrt war"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Das USB-Gerät wurde angeschlossen, als das Android-Gerät gesperrt war. Du musst erst das Android-Gerät entsperren und dann das USB-Gerät noch einmal anschließen, damit du es verwenden kannst."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Verdächtige USB-Aktivitäten"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB-Datensignal wurde deaktiviert."</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 332fb1b47585..25a787c5d06b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Ξεκαρφίτσωμα"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Ξεκαρφίτσωμα <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Πληροφορίες εφαρμογής"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Στοχευόμενοι χρήστες για Άμεση κοινή χρήση"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Προτεινόμενες εφαρμογές"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Λίστα εφαρμογών"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Έναρξη επίδειξης…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Επαναφορά συσκευής…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad αριστερά"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad δεξιά"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad κέντρο"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Πλαίσιο ρυθμίσεων τύπου αυτόματου κλικ"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Αριστερό κλικ"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Παύση"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Θέση"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"έστειλε μια εικόνα"</string>
@@ -2269,7 +2270,7 @@
<string name="resolver_cross_profile_blocked" msgid="3014597376026044840">"Αποκλείστηκε από τον διαχειριστή IT"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Δεν είναι δυνατή η κοινοποίηση αυτού του περιεχομένου με εφαρμογές εργασιών"</string>
<string name="resolver_cant_access_work_apps_explanation" msgid="1129960195389373279">"Δεν είναι δυνατό το άνοιγμα αυτού του περιεχομένου με εφαρμογές εργασιών"</string>
- <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Δεν είναι δυνατή η κοινοποίηση αυτού του περιεχομένου με προσωπικές εφαρμογές"</string>
+ <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="1535946298236678122">"Οι εφαρμογές εργασιών τέθηκαν σε παύση"</string>
<string name="resolver_switch_on_work" msgid="4527096360772311894">"Αναίρεση παύσης"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Χάρτες"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Εφαρμογές"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Δεν είναι δυνατή πλέον η αναγνώριση των δακτυλικών αποτυπωμάτων σας. Ρυθμίστε ξανά τη λειτουργία Ξεκλείδωμα με δακτυλικό αποτύπωμα."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Σύνδεση συσκευής USB σε κατάσταση κλειδώματος"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Η συσκευή USB είναι συνδεδεμένη, όταν το Android είναι κλειδωμένο. Για να χρησιμοποιήσετε τη συσκευή, ξεκλειδώστε πρώτα το Android και, στη συνέχεια, επανατοποθετήστε τη συσκευή USB για να τη χρησιμοποιήσετε."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Ύποπτη δραστηριότητα USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Το σήμα δεδομένων USB έχει απενεργοποιηθεί."</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 74feb323b4dc..886befff643f 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Unpin"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Unpin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"App info"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Direct share targets"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"App suggestions"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"App list"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Starting demo…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Resetting device…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad left"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad right"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centre"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Autoclick type settings panel"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Left-click"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Applications"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Your fingerprints can no longer be recognised. Set up Fingerprint Unlock again."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB device plugged in when locked"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB device is plugged in when Android is locked. To use the device, please unlock Android first and then reinsert the USB device to use it."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Suspicious USB activity"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB data signal has been disabled."</string>
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 9b7764ef0475..33bbc6faba3f 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Unpin"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Unpin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"App info"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Direct share targets"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"App suggestions"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"App list"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Starting demo…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Resetting device…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Center"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Autoclick type settings panel"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Left click"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Right click"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Double click"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Drag"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Applications"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Your fingerprints can no longer be recognized. Set up Fingerprint Unlock again."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB device plugged in when locked"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB device is plugged in when Android is locked. To use device, please unlock Android first and then reinsert USB device to use it."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Suspicious USB activity"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB data signal has been disabled."</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 51148ae3be1d..f0a9c2a27ddc 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Unpin"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Unpin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"App info"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Direct share targets"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"App suggestions"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"App list"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Starting demo…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Resetting device…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad left"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad right"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centre"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Autoclick type settings panel"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Left-click"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Applications"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Your fingerprints can no longer be recognised. Set up Fingerprint Unlock again."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB device plugged in when locked"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB device is plugged in when Android is locked. To use the device, please unlock Android first and then reinsert the USB device to use it."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Suspicious USB activity"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB data signal has been disabled."</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 0b9bb83b6a4a..8fcb412154cc 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Unpin"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Unpin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"App info"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Direct share targets"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"App suggestions"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"App list"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Starting demo…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Resetting device…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad left"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad right"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centre"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Autoclick type settings panel"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Left-click"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Applications"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Your fingerprints can no longer be recognised. Set up Fingerprint Unlock again."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB device plugged in when locked"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB device is plugged in when Android is locked. To use the device, please unlock Android first and then reinsert the USB device to use it."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Suspicious USB activity"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB data signal has been disabled."</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 07c66ead87df..f46a4d4abb40 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Dejar de fijar"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Dejar de fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Información de apps"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Objetivos de uso compartido directo"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Sugerencias de aplicaciones"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista de apps"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Iniciando demostración…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Restableciendo dispositivo…"</string>
@@ -2251,6 +2248,14 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pad direccional: centro"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel de configuración del tipo de clic automático"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic izquierdo"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
+ <skip />
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posición"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el bucket RESTRICTED"</string>
@@ -2527,12 +2532,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplicaciones"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Ya no se pueden reconocer tus huellas dactilares. Vuelve a configurar el Desbloqueo con huellas dactilares."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Dispositivo USB conectado cuando el dispositivo está bloqueado"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"El dispositivo USB está conectado cuando Android está bloqueado. Para usar el dispositivo, primero desbloquea Android y, luego, vuelve a insertar el dispositivo USB."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Actividad de USB sospechosa"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Se inhabilitó la señal de datos por USB."</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f035d5bbceaf..d5948972ec9c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"No fijar"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"No fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Información de la app"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Objetivos de compartición directa"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Sugerencias de aplicaciones"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista de aplicaciones"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Iniciando demostración…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Restableciendo dispositivo…"</string>
@@ -2249,14 +2246,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Cruceta: izquierda"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Cruceta: derecha"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Cruceta: centro"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel de ajustes del tipo de clic automático"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic izquierdo"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posición"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha enviado una imagen"</string>
@@ -2531,12 +2532,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplicaciones"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Tus huellas digitales ya no pueden reconocerse. Vuelve a configurar Desbloqueo con huella digital."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Dispositivo USB conectado con el dispositivo bloqueado"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"El dispositivo USB está conectado cuando Android está bloqueado. Para usar el dispositivo, desbloquea Android primero y, a continuación, vuelve a insertar el dispositivo USB para usarlo."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Actividad USB sospechosa"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"La señal de datos USB se ha inhabilitado."</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 1e299a609bd2..5e961f4fcae8 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -318,7 +318,7 @@
<string name="foreground_service_tap_for_details" msgid="9078123626015586751">"Aku ja andmekasutuse üksikasjade nägemiseks puudutage"</string>
<string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="8974401416068943888">"Turvarežiim"</string>
- <string name="android_system_label" msgid="5974767339591067210">"Android-süsteem"</string>
+ <string name="android_system_label" msgid="5974767339591067210">"Androidi süsteem"</string>
<string name="user_owner_label" msgid="8628726904184471211">"Lülitu isiklikule profiilile"</string>
<string name="managed_profile_label" msgid="7316778766973512382">"Lülitu tööprofiilile"</string>
<string name="user_owner_app_label" msgid="1553595155465750298">"Lülita <xliff:g id="APP_NAME">%1$s</xliff:g> isiklikule profiilile"</string>
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Vabasta"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Vabasta <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Rakenduse teave"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Otsejagamise sihtmärgid"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Rakenduste soovitused"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Rakenduste loend"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demo käivitamine …"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Seadme lähtestamine …"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Suunaklahvistiku keskmine nupp"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automaatkliki tüübi seadete paneel"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Vasakklikk"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Paremklikk"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Topeltklikk"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Lohista"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Keri"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Peata"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Asukoht"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Rakendused"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Teie sõrmejälgi ei saa enam tuvastada. Seadistage sõrmejäljega avamine uuesti."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-seade ühendati, kui seade oli lukus"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-seade ühendati, kui Android oli lukustatud. Seadme kasutamiseks avage esmalt Android ja ühendage siis USB-seade uuesti, et seda kasutada."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Kahtlane tegevus USB-ga"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB andmesignaal on keelatud."</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 177449ccb494..0e450d1a0a4e 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Kendu aingura"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Kendu aingura <xliff:g id="LABEL">%1$s</xliff:g> aplikazioari"</string>
<string name="app_info" msgid="6113278084877079851">"Aplikazioari buruzko informazioa"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Partekatze zuzenen helburuak"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Aplikazioen iradokizunak"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Aplikazioen zerrenda"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demoa abiarazten…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Gailua berrezartzen…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Norabide-kontrolagailuko ezkerreko botoia"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Norabide-kontrolagailuko eskuineko botoia"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Norabide-kontrolagailuko erdiko botoia"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automatikoki klik egiteko eginbide motaren ezarpenen panela"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Egin klik ezkerreko botoiarekin"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausatu"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Ezarri posizioan"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"erabiltzaileak irudi bat bidali du"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikazioak"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Zure hatz-markak ez dira ezagutzen jada. Konfiguratu berriro hatz-marka bidez desblokeatzeko eginbidea."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB bidezko gailua blokeatuta zegoen bitartean entxufatu da"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB bidezko gailua entxufatuta dago Android blokeatuta dagoenean. Gailua erabiltzeko, desblokeatu Android eta entxufatu berriro USB bidezko gailua hura erabiltzeko."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"USB bidezko jarduera susmagarriak"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB bidezko datu-seinalea desgaitu da."</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e0a8c1b67cb5..4334713515d9 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"برداشتن سنجاق"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"برداشتن سنجاق <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"اطلاعات برنامه"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"هدف‌های هم‌رسانی مستقیم"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"پیشنهادهای برنامه"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"فهرست برنامه"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"در حال شروع نسخه نمایشی…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"در حال بازنشانی دستگاه…"</string>
@@ -2248,14 +2245,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"پد کنترل چپ"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"پد کنترل راست"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"پد کنترل وسط"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"پانل تنظیمات نوع کلیک خودکار"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"کلیک چپ"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"کلیک راست"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"دوکلیک کردن"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"کشیدن"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"پیمایش"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"توقف موقت"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"موقعیت"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"تصویری ارسال کرد"</string>
@@ -2530,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"نقشه"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"برنامه‌ها"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"اثر انگشتانتان دیگر قابل‌شناسایی نیست. «قفل‌گشایی با اثر انگشت» را دوباره راه‌اندازی کنید."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"‏دستگاه USB هنگام قفل بودن وصل شده است"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"‏دستگاه USB هنگام قفل بودن Android متصل شده است. برای استفاده از دستگاه، لطفاً ابتدا قفل Android را باز کنید و سپس دستگاه USB را دوباره وارد کنید."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"‏فعالیت مشکوک USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"‏نشانِ داده USB غیرفعال شده است."</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 1b53196c9808..5e3913e86d8b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Irrota"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Irrota <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Sovellustiedot"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Suorajaon vastaanottajat"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Sovellusehdotukset"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Sovelluslista"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Aloitetaan esittelyä…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Palautetaan asetuksia…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Suuntanäppäimistö: vasen painike"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Suuntanäppäimistö: oikea painike"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Suuntanäppäimistö: keskipainike"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automaattisen klikkaustyypin asetuspaneeli"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Ykköspainike"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Keskeytä"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Sijainti"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"lähetti kuvan"</string>
@@ -2484,7 +2485,7 @@
<string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Takaisin"</string>
<string name="unarchival_session_app_label" msgid="6811856981546348205">"Odottaa…"</string>
<string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Satellite SOS on nyt käytettävissä"</string>
- <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Voit lähettää viestin hätäkeskukseen, jos sinulla ei ole mobiili‑ tai Wi-Fi-verkkoyhteyttä. Google Messages täytyy valita oletusviestisovellukseksi."</string>
+ <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Voit lähettää viestin hätäkeskukseen, jos sinulla ei ole mobiili‑ tai Wi-Fi-verkkoyhteyttä. Google Messagesin on oltava oletustekstiviestisovelluksesi."</string>
<string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Satellite SOS ei tueta"</string>
<string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Satellite SOS ei tueta tällä laitteella"</string>
<string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Satellite SOS ei ole otettu käyttöön"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Sovellukset"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Sormenjälkiäsi ei voi enää tunnistaa. Ota sormenjälkiavaus uudelleen käyttöön."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-laite kytkettynä, kun lukitus on päällä"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-laite on kytkettynä, kun Android on lukittu. Jos haluat käyttää laitetta, avaa ensin Androidin lukitus ja kytke USB-laite uudelleen."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Epäilyttävää USB-toimintaa"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB-datasignaali on poistettu käytöstä."</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index d742d87f7ed7..6ef3e21c6a63 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Annuler l\'épinglage"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Annuler l\'épinglage de <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Détails de l\'appli"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Cibles du partage direct"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Applis suggérées"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Liste d\'applis"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Démarrage de la démonstration en cours…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Réinitialisation de l\'appareil en cours…"</string>
@@ -2249,14 +2246,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Pavé directionnel – gauche"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Pavé directionnel – droite"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pavé directionnel – centre"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panneau de configuration des paramètres de type clic automatique"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic gauche"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a envoyé une image"</string>
@@ -2531,12 +2532,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Applications"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Vos empreintes digitales ne peuvent plus être reconnues. Reconfigurez le Déverrouillage par empreinte digitale."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"L\'appareil USB est branché quand Android est verrouillé"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"L\'appareil USB est branché quand Android est verrouillé. Pour utiliser l\'appareil, veuillez d\'abord déverrouiller Android, puis réinsérer l\'appareil USB."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Activité USB suspecte"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Le signal de données USB a été désactivé."</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index f0727d69c325..4fd8601a1d8a 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Retirer"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Retirer <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Infos sur l\'appli"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Cibles de partage direct"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Suggestions d\'applications"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Liste des applications"</string>
<string name="negative_duration" msgid="1938335096972945232">"− <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Lancement de la démo…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Réinitialisation…"</string>
@@ -2249,14 +2246,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Pavé directionnel - Gauche"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Pavé directionnel - Droite"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pavé directionnel - Centre"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panneau des paramètres du type de clic automatique"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic gauche"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a envoyé une image"</string>
@@ -2531,12 +2532,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Applications"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Vos empreintes ne peuvent plus être reconnues. Reconfigurez le déverrouillage par empreinte digitale."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Appareil USB branché alors que l\'appareil Android est verrouillé"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"L\'appareil USB est branché alors que l\'appareil Android est verrouillé. Pour utiliser l\'appareil, veuillez d\'abord déverrouiller Android, puis brancher à nouveau l\'appareil USB."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Activité USB suspecte"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Le signal de données USB a été désactivé."</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index bb41a4f5fd3d..4ce3fc33b7e9 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Deixar de fixar"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Deixar de fixar a <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Información da app"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Destinatarios da función de compartir directamente"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Suxestións de aplicacións"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista de aplicacións"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Iniciando demostración…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Restablecendo dispositivo…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Cruceta: esquerda"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Cruceta: dereita"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Cruceta: centro"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel de configuración do tipo de clic automático"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic co botón esquerdo do rato"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausa"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posición"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviouse unha imaxe"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Mapas"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplicacións"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Xa non se recoñecen as túas impresións dixitais. Configura de novo o desbloqueo dactilar."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Dispositivo USB conectado cando Android está bloqueado"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"O dispositivo USB está conectado cando Android está bloqueado. Para usalo, primeiro desbloquea Android e despois volve inserir o dispositivo USB."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Actividade USB sospeitosa"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Desactivouse o indicador de datos USB."</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index ff32df0b26fe..fcba3feb7819 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"અનપિન કરો"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g>ને અનપિન કરો"</string>
<string name="app_info" msgid="6113278084877079851">"ઍપની માહિતી"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"સીધા શેર કરવાના લક્ષ્યો"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"ઍપના સૂચનો"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"ઍપની સૂચિ"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ડેમો પ્રારંભ કરી રહ્યાં છે…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"ઉપકરણ ફરીથી સેટ કરી રહ્યાં છે…"</string>
@@ -2248,14 +2245,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ડી-પૅડ ડાબે"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ડી-પૅડ જમણે"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ડી-પૅડ મધ્યમાં"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ઑટોક્લિક પ્રકારના સેટિંગની પૅનલ"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ડાબું ક્લિક કરો"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"રાઇટ ક્લિક કરો"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"બે વાર ક્લિક કરો"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ખેંચો"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"સ્ક્રોલ કરો"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"થોભાવો"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"સ્થિતિ"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"છબી મોકલી"</string>
@@ -2530,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"ઍપ્લિકેશનો"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"તમારી ફિંગરપ્રિન્ટને હવેથી ઓળખી શકાશે નહીં. ફિંગરપ્રિન્ટ અનલૉક સુવિધાનું ફરી સેટઅપ કરો."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"લૉક કરેલું હોય ત્યારે USB ડિવાઇસ પ્લગ-ઇન હોય છે"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android લૉક હોય ત્યારે USB ડિવાઇસ પ્લગ-ઇન હોય છે. ડિવાઇસનો ઉપયોગ કરવા માટે, કૃપા કરીને પહેલા Android અનલૉક કરો અને પછી USB ડિવાઇસનો ઉપયોગ કરવા માટે તેને ફરી શામેલ કરો."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"શંકાસ્પદ USB ઍક્ટિવિટી"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB ડેટા સિગ્નલ બંધ કરવામાં આવ્યું છે."</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 393316b2386e..66f0ced39df6 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -329,7 +329,7 @@
<string name="permgroupdesc_location" msgid="1995955142118450685">"इस डिवाइस की जगह तक पहुंचने दें"</string>
<string name="permgrouplab_calendar" msgid="6426860926123033230">"कैलेंडर"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"आपके कैलेंडर को ऐक्सेस करने की अनुमति"</string>
- <string name="permgrouplab_sms" msgid="795737735126084874">"मैसेज (एसएमएस)"</string>
+ <string name="permgrouplab_sms" msgid="795737735126084874">"एसएमएस"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"मैसेज (एसएमएस) भेजें और देखें"</string>
<string name="permgrouplab_storage" msgid="17339216290379241">"फ़ाइल"</string>
<string name="permgroupdesc_storage" msgid="5378659041354582769">"अपने डिवाइस में मौजूद फ़ाइलों का ऐक्सेस दें"</string>
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"अनपिन करें"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> को अनपिन करें"</string>
<string name="app_info" msgid="6113278084877079851">"ऐप्लिकेशन की जानकारी"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"सीधे तौर पर कॉन्टेंट शेयर करने के लिए चुने गए लोग या ग्रुप"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"सुझाए गए ऐप्लिकेशन"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"ऐप्लिकेशन की सूची"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"डेमो प्रारंभ हो रहा है…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"डिवाइस फिर से रीसेट कर रहा है…"</string>
@@ -2248,14 +2245,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"डी-पैड का बाईं ओर वाला बटन"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"डी-पैड का दाईं ओर वाला बटन"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"डी-पैड का बीच वाला बटन"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"अपने-आप क्लिक होने की सुविधा वाली सेटिंग का पैनल"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"लेफ़्ट क्लिक करें"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"राइट क्लिक करें"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"दो बार क्लिक करें"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"खींचें और छोड़ें"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"स्क्रोल करें"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"रोकें"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"पोज़िशन"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"एक इमेज भेजी गई"</string>
@@ -2530,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"मैप"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"ऐप्लिकेशन"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"अब आपके फ़िंगरप्रिंट की पहचान नहीं की जा सकती. फ़िंगरप्रिंट अनलॉक की सुविधा को दोबारा सेट अप करें."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"यूएसबी डिवाइस को, Android डिवाइस के लॉक होने के दौरान प्लग इन किया गया"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"यूएसबी डिवाइस को, Android डिवाइस के लॉक होने के दौरान प्लग इन किया गया. यूएसबी डिवाइस का इस्तेमाल करने के लिए, कृपया पहले Android डिवाइस को अनलॉक करें. इसके बाद, यूएसबी को फिर से इंसर्ट करें."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"यूएसबी से कोई संदिग्ध गतिविधि की गई"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"यूएसबी से डेटा सिग्नल भेजने की प्रोसेस बंद कर दी गई है."</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index cc4d29689743..aadf1185883b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Otkvači"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Otkvači sudionika <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informacije o aplikaciji"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Osoba/skupina za izravno dijeljenje"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Prijedlozi aplikacija"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Popis aplikacija"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Pokretanje demo-načina..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Vraćanje uređaja na zadano…"</string>
@@ -2251,6 +2248,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"U središtu plohe za smjerove"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Ploča postavki vrste automatskog klika"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Lijevi klik"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Desni klik"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dvostruki klik"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Povuci"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Pomakni se"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauziraj"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicija"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string>
@@ -2527,12 +2528,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Karte"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikacije"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Vaši se otisci prstiju više ne prepoznaju. Ponovo postavite otključavanje otiskom prsta."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB uređaj priključen je kada je zaključan"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB uređaj priključen je kad je Android zaključan. Da biste upotrebljavali uređaj, najprije otključajte Android, a zatim ponovno umetnite USB uređaj da biste ga upotrebljavali."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Sumnjiva aktivnost USB-a"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB podatkovni signal je onemogućen."</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index ddfef1aae499..39a4cfcbe0c7 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Feloldás"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> rögzítésének feloldása"</string>
<string name="app_info" msgid="6113278084877079851">"Alkalmazásinfó"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Közvetlen megosztási lehetőségek"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Alkalmazásjavaslatok"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Alkalmazáslista"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Bemutató indítása…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Eszköz visszaállítása…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad – balra"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad – jobbra"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad – középre"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automatikus kattintás típusának beállításai panel"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Kattintás bal egérgombbal"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Szüneteltetés"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozíció"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"képet küldött"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Térkép"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Alkalmazások"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Az ujjlenyomata már nem ismerhető fel. Állítsa be újra a Feloldás ujjlenyomattal funkciót."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-eszköz zárolt állapotban csatlakoztatva"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Az USB-eszköz csatlakoztatása az Android rendszer zárolt állapotában történt. Az eszköz használatához először oldja fel az Android zárolását, majd helyezze be újra az USB-eszközt."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Gyanús USB-tevékenység"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Az USB-adatjel le lett tiltva."</string>
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 92633245988e..f4b83f2a6540 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -2248,14 +2248,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad-ի «Ձախ» կոճակ"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad-ի «Աջ» կոճակ"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad-ի «Կենտրոն» կոճակ"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Ավտոմատ սեղմման տեսակի կարգավորումների վահանակ"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Ձախ սեղմում"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Դադարեցնել"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Դիրքը"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>՝"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"օգտատերը պատկեր է ուղարկել"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 86f711483ed1..ce9a7f6c6bea 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Lepas pin"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Lepas sematan <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Info aplikasi"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Target berbagi langsung"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Saran aplikasi"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Daftar aplikasi"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Memulai demo..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Mereset perangkat..."</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Kiri"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Kanan"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Tengah"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel setelan jenis klik otomatis"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Klik kiri"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Jeda"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posisi"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"mengirim gambar"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikasi"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Sidik jari Anda tidak dapat dikenali lagi. Siapkan Buka dengan Sidik Jari lagi."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Perangkat USB dicolokkan saat terkunci"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Perangkat USB dicolokkan saat Android terkunci. Untuk menggunakan perangkat, buka kunci Android terlebih dahulu, lalu pasang kembali perangkat USB untuk menggunakannya."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Aktivitas USB yang mencurigakan"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Sinyal data USB telah dinonaktifkan."</string>
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 360e3d9815a0..b80efc7878f5 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Losa"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Losa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Forritsupplýsingar"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Deila beint með"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Tillögð forrit"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Forritalisti"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Byrjar kynningu…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Endurstillir tækið…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Vinstrihnappur stýriflatar"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Hægrihnappur stýriflatar"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Miðjuhnappur stýriflatar"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Stillingasvæði fyrir tegund sjálfvirks smells"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Vinstrismellur"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Hlé"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Staðsetning"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sendi mynd"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Kort"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Forrit"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Ekki er lengur hægt að bera kennsl á fingraförin þín. Settu fingrafarskenni upp aftur."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-tæki stungið í samband á meðan tæki var læst"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-tæki stungið í samband á meðan Android-tækið var læst. Byrjaðu á því að taka Android-tækið úr lás og stingdu síðan USB-tækinu í samband til að nota það."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Grunsamleg USB-virkni"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Slökkt var á USB-gagnamerki."</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1914ea5ec6b5..3ca9f7f8c7f1 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -333,11 +333,11 @@
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"Possono inviare e visualizzare SMS"</string>
<string name="permgrouplab_storage" msgid="17339216290379241">"File"</string>
- <string name="permgroupdesc_storage" msgid="5378659041354582769">"accedere ai file sul tuo dispositivo"</string>
+ <string name="permgroupdesc_storage" msgid="5378659041354582769">"Possono accedere ai file sul tuo dispositivo"</string>
<string name="permgrouplab_readMediaAural" msgid="1858331312624942053">"Musica e audio"</string>
- <string name="permgroupdesc_readMediaAural" msgid="7565467343667089595">"accedere a musica e audio sul tuo dispositivo"</string>
+ <string name="permgroupdesc_readMediaAural" msgid="7565467343667089595">"Possono accedere a musica e audio sul tuo dispositivo"</string>
<string name="permgrouplab_readMediaVisual" msgid="4724874717811908660">"Foto e video"</string>
- <string name="permgroupdesc_readMediaVisual" msgid="4080463241903508688">"accedere a foto e video sul tuo dispositivo"</string>
+ <string name="permgroupdesc_readMediaVisual" msgid="4080463241903508688">"Possono accedere a foto e video sul tuo dispositivo"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"Microfono"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"Possono registrare audio"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Attività fisica"</string>
@@ -345,7 +345,7 @@
<string name="permgrouplab_camera" msgid="9090413408963547706">"Fotocamera"</string>
<string name="permgroupdesc_camera" msgid="7585150538459320326">"Possono scattare foto e registrare video"</string>
<string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Dispositivi nelle vicinanze"</string>
- <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"rilevare e connettersi a dispositivi nelle vicinanze"</string>
+ <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"Possono rilevare e connettersi a dispositivi nelle vicinanze"</string>
<string name="permgrouplab_calllog" msgid="7926834372073550288">"Registri chiamate"</string>
<string name="permgroupdesc_calllog" msgid="2026996642917801803">"Possono leggere e modificare il registro chiamate del telefono"</string>
<string name="permgrouplab_phone" msgid="570318944091926620">"Telefono"</string>
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Stacca"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Sblocca <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informazioni app"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Target di condivisione diretta"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"App suggerite"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Elenco di app"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Avvio della demo…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Reset del dispositivo…"</string>
@@ -2249,14 +2246,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad - Sinistra"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad - Destra"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad - Centro"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Riquadro impostazioni del tipo di clic automatico"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic sinistro"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Clic con il tasto destro del mouse"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Doppio clic"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Trascina"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scorri"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Metti in pausa"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posizione"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha inviato un\'immagine"</string>
@@ -2531,12 +2528,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Applicazioni"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Non è più possibile riconoscere le tue impronte. Riconfigura lo Sblocco con l\'Impronta."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Dispositivo USB collegato quando bloccato"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Il dispositivo USB è collegato quando Android è bloccato. Per usare il dispositivo, sblocca prima Android e poi reinserisci il dispositivo USB."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Attività USB sospetta"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"L\'indicatore di dati USB è stato disattivato."</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 5e0df4708c03..cfa0987c15d4 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1786,7 +1786,7 @@
<string name="hearing_aids_feature_name" msgid="1125892105105852542">"מכשירי שמיעה"</string>
<string name="hearing_device_status_disconnected" msgid="497547752953543832">"מנותק"</string>
<string name="hearing_device_status_connected" msgid="2149385149669918764">"מחובר"</string>
- <string name="hearing_device_status_active" msgid="4770378695482566032">"פעיל"</string>
+ <string name="hearing_device_status_active" msgid="4770378695482566032">"מצב פעיל"</string>
<string name="hearing_device_status_loading" msgid="5717083847663109747">"בטעינה"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. שירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. שירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת."</string>
@@ -2249,14 +2249,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"‏לחצן שמאלי ב-Dpad"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"‏לחצן ימני ב-Dpad"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"‏לחצן אמצעי ב-Dpad"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"חלונית ההגדרות של סוג הקליק האוטומטי"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"לחיצה שמאלית"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"השהיה"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"מיקום"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"נשלחה תמונה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index ac37d558e8bb..ad770aaae3ac 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"固定を解除"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> の固定を解除"</string>
<string name="app_info" msgid="6113278084877079851">"アプリ情報"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"ダイレクト シェア ターゲット"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"アプリの候補"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"アプリリスト"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"デモを開始しています…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"デバイスをリセットしています…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad: 中央"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"自動クリックの種類の設定パネル"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"左クリック"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"右クリック"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ダブルクリック"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ドラッグ"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"スクロール"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"一時停止"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"マップ"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"アプリ"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"指紋を認識できなくなりました。指紋認証をもう一度設定してください。"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"ロック状態で USB デバイスが接続されました"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android がロックされている状態で USB デバイスが接続されています。デバイスを使用するには、まず Android のロックを解除してから、USB デバイスを再挿入してください。"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"不審な USB アクティビティ"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB データシグナルが無効になっています。"</string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 2dee93b1dc24..481c422ae22c 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"ჩამაგრების მოხსნა"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g>-ის ჩამაგრების მოხსნა"</string>
<string name="app_info" msgid="6113278084877079851">"აპის შესახებ"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"პირდაპირი გაზიარების მიზნები"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"აპის შეთავაზებები"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"აპების სია"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"მიმდინარეობს დემონსტრაციის დაწყება…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"მიმდინარეობს მოწყობილობის გადაყენება…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ცენტრი"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ავტოდაწკაპუნების ტიპის პარამეტრების არე"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"მარცხენა დაწკაპუნება"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"მარჯვენა დაწკაპუნება"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ორმაგი დაწკაპუნება"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ჩავლება"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"გადაადგილება"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"პაუზა"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"პოზიცია"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"აპლიკაციები"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"თქვენი თითის ანაბეჭდის ამოცნობა ვეღარ ხერხდება. ხელახლა დააყენეთ ანაბეჭდით განბლოკვა."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB მოწყობილობა ჩართულია, როდესაც ჩაკეტილია"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB მოწყობილობა ჩართულია, როდესაც Android ჩაკეტილია. მოწყობილობის გამოსაყენებლად ჯერ განბლოკეთ Android და შემდეგ ხელახლა ჩადეთ USB მოწყობილობა მის გამოსაყენებლად."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"საეჭვო USB აქტივობა"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB მონაცემთა სიგნალი გამორთულია."</string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 6655e5d31590..70412bed6215 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Босату"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> босату"</string>
<string name="app_info" msgid="6113278084877079851">"Қолданба ақпараты"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Тікелей бөлісу опциялары"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Қолданба ұсыныстары"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Қолданбалар тізімі"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Демо нұсқасы іске қосылуда..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Құрылғы бастапқы күйге қайтарылуда..."</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Сол жақ Dpad түймесі"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Оң жақ Dpad түймесі"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Ортаңғы Dpad түймесі"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Автоматты басу түрі параметрлері панелі"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Сол жағын басу"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Кідірту"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Орналастыру"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"сурет жіберілді"</string>
@@ -2266,7 +2267,7 @@
<string name="resolver_work_tab" msgid="2690019516263167035">"Жұмыс"</string>
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Жеке көру"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Жұмыс деректерін көру"</string>
- <string name="resolver_cross_profile_blocked" msgid="3014597376026044840">"Әкімшіңіз бөгеген"</string>
+ <string name="resolver_cross_profile_blocked" msgid="3014597376026044840">"Әкімшіңіз блоктаған"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="9071442683080586643">"Бұл контентті жұмыс қолданбаларымен бөлісу мүмкін емес."</string>
<string name="resolver_cant_access_work_apps_explanation" msgid="1129960195389373279">"Бұл контентті жұмыс қолданбаларымен ашу мүмкін емес."</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"Бұл контентті жеке қолданбалармен бөлісу мүмкін емес."</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Қолданбалар"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Саусағыңыздың іздері бұдан былай танылмайды. Саусақ ізімен ашу функциясын қайта реттеу"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB құрылғысы құлыптаулы кезде жалғанған"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB құрылғысы Android құрылғысы құлыптаулы кезде жалғанған. Құрылғыны пайдалану үшін алдымен Android құрылғысының құлпын ашып, содан кейін USB құрылғысын қайта енгізіңіз."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"USB-ге қатысты күдікті әрекет"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB дерек сигналы өшірілді."</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 3d78797d9a70..fdd522bd0ede 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"មិនខ្ទាស់"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"ដកខ្ទាស់ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"ព័ត៌មាន​កម្មវិធី"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"គោលដៅចែករំលែកដោយផ្ទាល់"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"ការណែនាំកម្មវិធី"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"បញ្ជីកម្មវិធី"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"កំពុងចាប់ផ្តើមការបង្ហាញសាកល្បង…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"កំពុងកំណត់ឧបករណ៍ឡើងវិញ…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad កណ្ដាល"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ផ្ទាំងការកំណត់ប្រភេទចុចស្វ័យប្រវត្តិ"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ចុចម៉ៅស៍ខាងឆ្វេង"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"ចុចម៉ៅស៍ខាងស្ដាំ"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ចុចពីរដង"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"អូស"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"រំកិល"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ផ្អាក"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"ទីតាំង"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់​ទៅក្នុងធុង​ដែលបានដាក់កំហិត"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"ផែនទី"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"កម្មវិធី"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"លែងអាចសម្គាល់ស្នាមម្រាមដៃរបស់អ្នកបានទៀតហើយ។ សូមរៀបចំការដោះសោ​ដោយស្កេន​ស្នាមម្រាមដៃម្ដងទៀត។"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"បានដោតឧបករណ៍ USB នៅពេលជាប់សោ"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"ឧបករណ៍ USB ត្រូវបានដោត នៅពេល Android ត្រូវបានចាក់សោ។ ដើម្បីប្រើឧបករណ៍ សូមដោះសោ Android ជាមុនសិន បន្ទាប់មកដោតឧបករណ៍ USB ឡើងវិញ ដើម្បីប្រើប្រាស់វា។"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"សកម្មភាព USB ដែលគួរឱ្យសង្ស័យ"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"សញ្ញាទិន្នន័យ USB ត្រូវបានបិទ។"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 1d89ad7c08e5..887938cce097 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"ಅನ್‌ಪಿನ್"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> ಅನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಿ"</string>
<string name="app_info" msgid="6113278084877079851">"ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"ನೇರ ಹಂಚಿಕೊಳ್ಳುವಿಕೆ ಟಾರ್ಗೆಟ್‌ಗಳು"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"ಆ್ಯಪ್ ಸಲಹೆಗಳು"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"ಆ್ಯಪ್ ಪಟ್ಟಿ"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ಡೆಮೋ ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"ಸಾಧನ ಮರುಹೊಂದಿಸಲಾಗುತ್ತಿದೆ..."</string>
@@ -2248,14 +2245,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ನ ಎಡಭಾಗದ ಬಟನ್"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ನ ಬಲಭಾಗದ ಬಟನ್"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ನ ಮಧ್ಯದ ಬಟನ್"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ಆಟೋಕ್ಲಿಕ್ ಪ್ರಕಾರದ ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಪ್ಯಾನೆಲ್"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ಎಡ-ಕ್ಲಿಕ್"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"ಬಲ-ಕ್ಲಿಕ್"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ಡಬಲ್‌ ಕ್ಲಿಕ್"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ವಿರಾಮಗೊಳಿಸಿ"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ಸ್ಥಾನ"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್‌ಗೆ ಹಾಕಲಾಗಿದೆ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string>
@@ -2530,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"ಆ್ಯಪ್‌ಗಳು"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್‌ಗಳನ್ನು ಇನ್ನು ಮುಂದೆ ಗುರುತಿಸಲಾಗುವುದಿಲ್ಲ. ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್‌ಲಾಕ್ ಅನ್ನು ಮತ್ತೊಮ್ಮೆ ಸೆಟಪ್ ಮಾಡಿ."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"ಲಾಕ್ ಆಗಿರುವಾಗ USB ಸಾಧನವನ್ನು ಪ್ಲಗ್-ಇನ್ ಮಾಡಲಾಗುತ್ತದೆ"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android ಲಾಕ್ ಆಗಿರುವಾಗ USB ಸಾಧನವನ್ನು ಪ್ಲಗ್-ಇನ್ ಮಾಡಲಾಗುತ್ತದೆ. ಸಾಧನವನ್ನು ಬಳಸಲು, ಮೊದಲು Android ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ ಮತ್ತು ನಂತರ ಅದನ್ನು ಬಳಸಲು USB ಸಾಧನವನ್ನು ಪುನಃ ಸೇರಿಸಿ."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"ಅನುಮಾನಾಸ್ಪದ USB ಚಟುವಟಿಕೆ"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB ಡೇಟಾ ಸಿಗ್ನಲ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ad1bdae6fc30..fc392711bd57 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"고정 해제"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> 고정 해제"</string>
<string name="app_info" msgid="6113278084877079851">"앱 정보"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"직접 공유 타겟"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"앱 제안"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"앱 목록"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"데모 시작 중..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"기기 초기화 중..."</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"방향 패드 왼쪽"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"방향 패드 오른쪽"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"방향 패드 가운데"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"자동 클릭 유형 설정 패널"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"왼쪽 클릭"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"일시중지"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"위치"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"이미지 보냄"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"지도"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"애플리케이션"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"지문을 더 이상 인식할 수 없습니다. 지문 잠금 해제를 다시 설정하세요."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"잠금 상태에서 USB 기기가 연결됨"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android가 잠겨 있는 상태에서 USB 기기가 연결되었습니다. 기기를 사용하려면 먼저 Android를 잠금 해제한 다음 USB 기기를 다시 삽입하세요."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"의심스러운 USB 활동"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB 데이터 신호가 사용 중지됨"</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index cb4edb963c76..f8c0022f0f31 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Кадоодон алып коюу"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> бошотуу"</string>
<string name="app_info" msgid="6113278084877079851">"Колдонмо тууралуу"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Түздөн-түз бөлүшүлгөндөрдү алуучулар"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Сунушталган колдонмолор"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Колдонмолордун тизмеси"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Демо режим башталууда…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Түзмөк баштапкы абалга келтирилүүдө…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad\'дын сол баскычы"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad\'дын оң баскычы"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad\'дын ортоңку баскычы"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Авточыкылдатуу түрүнүн параметрлеринин панели"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Сол баскычын чыкылдатуу"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Тындыруу"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Орду"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"сүрөт жөнөттү"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Карталар"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Колдонмолор"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Манжаңыздын изи мындан ары таанылбайт. Манжа изи менен ачуу функциясын кайрадан тууралаңыз."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB түзмөк Android кулпуланып турганда туташтырылды"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB түзмөк Android кулпуланганда туташтырылды. Түзмөктү колдонуу үчүн алгач Android\'дин кулпусун ачып, USB түзмөктү кайрадан сайыңыз."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"USB\'ге байланыштуу шектүү аракет"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB сигналы өчүрүлдү."</string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 4b426c818179..429f3f79cf64 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"ຖອນປັກໝຸດ"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"ຖອດປັກມຸດ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"ຂໍ້ມູນແອັບ"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"ເປົ້າໝາຍການແບ່ງປັນໂດຍກົງ"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"ການແນະນຳແອັບ"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"ລາຍຊື່ແອັບ"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ກຳລັງເລີ່ມເດໂມ…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"ກຳລັງຣີເຊັດອຸປະກອນ…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ກາງ"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ແຜງການຕັ້ງຄ່າປະເພດການຄລິກອັດຕະໂນມັດ"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ຄລິກຊ້າຍ"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"ຄລິກຂວາ"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ຄລິກສອງເທື່ອ"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ລາກ"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ເລື່ອນ"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ຢຸດຊົ່ວຄາວ"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"ຕຳແໜ່ງ"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"ແຜນທີ່"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"ແອັບພລິເຄຊັນ"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"ລະບົບບໍ່ສາມາດຈຳແນກລາຍນິ້ວມືຂອງທ່ານໄດ້ອີກຕໍ່ໄປ. ກະລຸນາຕັ້ງຄ່າການປົດລັອກດ້ວຍລາຍນິ້ວມືອີກຄັ້ງ."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"ທ່ານສຽບອຸປະກອນ USB ໃນຂະນະທີ່ລັອກຢູ່"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"ທ່ານສຽບອຸປະກອນ USB ໃນຂະນະທີ່ Android ລັອກຢູ່. ເພື່ອໃຊ້ອຸປະກອນ, ກະລຸນາປົດລັອກ Android ກ່ອນແລ້ວຈຶ່ງສຽບອຸປະກອນ USB ອີກຄັ້ງເພື່ອນຳໃຊ້."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"ການເຄື່ອນໄຫວຂອງ USB ທີ່ໜ້າສົງໄສ"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"ສັນຍານຂໍ້ມູນຂອງ USB ຖືກປິດການນຳໃຊ້."</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 544cd4108e02..3ca681bffc63 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2090,12 +2090,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Atsegti"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Atsegti <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Programos informacija"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Tiesioginio bendrinimo paskirties vietos"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Siūlomos programos"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Programų sąrašas"</string>
<string name="negative_duration" msgid="1938335096972945232">"–<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Paleidžiama demonstracinė versija…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Įrenginys nustatomas iš naujo…"</string>
@@ -2250,14 +2247,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Valdymo pultas – kairėn"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Valdymo pultas – dešinėn"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Valdymo pultas – centras"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automatinio paspaudimo tipo nustatymų skydelis"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Spustelėti kairiuoju klavišu"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Spustelėti dešiniuoju klavišu"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dukart spustelėti"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Vilkti"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Slinkti"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pristabdyti"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicija"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"išsiuntė vaizdą"</string>
@@ -2532,12 +2529,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Žemėlapiai"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Programos"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Nebegalima atpažinti jūsų piršto atspaudų. Dar kartą nustatykite atrakinimą piršto atspaudu."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB įrenginys prijungtas, kai užrakintas"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB įrenginys prijungtas, kai „Android“ užrakintas. Jei norite naudoti įrenginį, pirmiausia atrakinkite „Android“, tada vėl įkiškite USB įrenginį, kad galėtumėte jį naudoti."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Įtartina USB veikla"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB duomenų signalas išjungtas."</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 02e93395237c..1e7ffd145eac 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Atspraust"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Atspraust lietotni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Lietotnes informācija"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Tiešās kopīgošanas adresāti"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Ieteicamās lietotnes"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lietotņu saraksts"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Notiek demonstrācijas palaišana..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Notiek ierīces atiestatīšana..."</string>
@@ -2249,14 +2246,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Virzienu slēdzis — pa kreisi"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Virzienu slēdzis — pa labi"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Virzienu slēdzis — centrs"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automātiskās klikšķināšanas veida iestatījumu panelis"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Noklikšķināt ar peles kreiso pogu"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pārtraukt"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozīcija"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"nosūtīts attēls"</string>
@@ -2531,12 +2532,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Lietojumprogrammas"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Jūsu pirkstu nospiedumus vairs nevar atpazīt. Vēlreiz iestatiet autorizāciju ar pirksta nospiedumu."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB ierīce tika pievienota, kad Android ierīce bija bloķēta"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB ierīce tika pievienota, kad Android ierīce bija bloķēta. Lai izmantotu ierīci, vispirms atbloķējiet Android ierīci un pēc tam atkārtoti pievienojiet USB ierīci."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Aizdomīgas darbības ar USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB datu signāls ir atspējots."</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index df101f24f158..c1a7c1dc5739 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Откачете"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Откачи <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Информации за апликација"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Директни цели на споделување"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Предлози за апликации"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Список со апликации"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Се вклучува демонстрацијата…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Се ресетира уредот…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Навигациско копче за налево"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Навигациско копче за надесно"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Навигациско копче за средина"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Табла со поставки за вид автоматско кликнување"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Кликни со лево копче"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Паузирај"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Позиционирај"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"испрати слика"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Карти"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Апликации"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Вашите отпечатоци веќе не може да се препознаат. Поставете „Отклучување со отпечаток“ повторно."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-уредот е приклучен кога е заклучен"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-уредот е приклучен кога Android е заклучен. За да го користите уредот, прво отклучете го Android, па вметнете го USB-уредот повторно за да го користите."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Сомнителна активност на USB-уредот"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Сигналот со податоци преку USB е оневозможен."</string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index b5ded52f10b7..5c31433e9456 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"അൺപിൻ ചെയ്യുക"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> അൺപിൻ ചെയ്യുക"</string>
<string name="app_info" msgid="6113278084877079851">"ആപ്പ് വിവരം"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"നേരിട്ടുള്ള പങ്കിടൽ ടാർഗറ്റുകൾ"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"ആപ്പ് നിർദ്ദേശങ്ങൾ"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"ആപ്പ് ലിസ്റ്റ്"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ഡെമോ ആരംഭിക്കുന്നു…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"ഉപകരണം പുനക്രമീകരിക്കുന്നു…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad സെന്റർ"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ഓട്ടോക്ലിക്ക് തരം ക്രമീകരണ പാനല്‍"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ഇടത് ക്ലിക്ക്"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"വലത്-ക്ലിക്ക്"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ഡബിൾ ക്ലിക്ക്"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"വലിച്ചിടുക"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"സ്‌ക്രോൾ ചെയ്യുക"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"താൽക്കാലികമായി നിർത്തുക"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"സ്ഥാനം"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"ആപ്പുകൾ"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"നിങ്ങളുടെ ഫിംഗർപ്രിന്റുകൾ ഇനി തിരിച്ചറിയാനാകില്ല. ഫിംഗർപ്രിന്റ് അൺലോക്ക് വീണ്ടും സജ്ജീകരിക്കുക."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"ലോക്കായിരിക്കുമ്പോഴാണ് USB ഉപകരണം പ്ലഗ്-ഇൻ ചെയ്തത്"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android ലോക്കായിരിക്കുമ്പോഴാണ് USB ഉപകരണം പ്ലഗ്-ഇൻ ചെയ്തത്. ഉപകരണം ഉപയോഗിക്കാൻ ആദ്യം Android അൺലോക്ക് ചെയ്യുക, ശേഷം USB ഉപകരണം വീണ്ടും ഇൻസേർട്ട് ചെയ്ത് ഉപയോഗിക്കുക."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"സംശയാസ്പദമായ USB ആക്റ്റിവിറ്റി"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB ഡാറ്റാ സിഗ്‌നൽ പ്രവർത്തനരഹിതമാക്കി."</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index a61bd7fbf1da..24637fa0b323 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Unpin"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g>-г тогтоосныг болиулах"</string>
<string name="app_info" msgid="6113278084877079851">"Аппын мэдээлэл"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Шууд хуваалцах сонголтууд"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Санал болгож буй аппууд"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Аппын жагсаалт"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Жишээг эхлүүлж байна…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Төхөөрөмжийг шинэчилж байна…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad зүүн"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad баруун"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad гол"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Автомат товшилтын төрлийн тохиргооны түр зуурын самбар"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Зүүн талыг товших"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Түр зогсоох"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Байрлал"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"зураг илгээсэн"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Газрын зураг"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Аппликэйшн"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Таны хурууны хээг цаашид таних боломжгүй. Хурууны хээгээр түгжээ тайлахыг дахин тохируулна уу."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Түгжээтэй үед USB төхөөрөмж залгаатай байна"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android-г түгжсэн үед USB төхөөрөмж залгаатай байна. Төхөөрөмжийг ашиглахын тулд эхлээд Android-н түгжээг тайлж, дараа нь USB төхөөрөмжийг ашиглахын тулд дахин оруулна уу."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"USB-н сэжигтэй үйл ажиллагаа"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB-н өгөгдлийн дохиог идэвхгүй болгосон."</string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 3f2e57f5163a..0717eb976261 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"अनपिन करा"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> ला अनपिन करा"</string>
<string name="app_info" msgid="6113278084877079851">"अ‍ॅप माहिती"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"थेट शेअर करण्यासंबंधी लक्ष्ये"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"अ‍ॅप सूचना"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"अ‍ॅप सूची"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"डेमो सुरू करत आहे..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"डिव्हाइस रीसेट करत आहे..."</string>
@@ -2248,14 +2245,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad डावीकडील"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad चे उजवीकडील"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad चे मधले"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ऑटोक्लिक प्रकाराचे सेटिंग्ज पॅनल"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"लेफ्ट क्लिक करा"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"राइट क्लिक करा"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"डबल क्लिक करा"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ड्रॅग करा"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"स्क्रोल करा"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"थांबवा"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"स्थिती"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"इमेज पाठवली आहे"</string>
@@ -2530,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"अ‍ॅप्लिकेशन"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"तुमची फिंगरप्रिंट यापुढे ओळखता येणार नाहीत. फिंगरप्रिंट अनलॉक पुन्हा सेट करा."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"लॉक केलेले असताना USB डिव्हाइस प्लग इन केले आहे"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android लॉक केलेले असताना USB डिव्हाइस प्लग इन केले आहे. डिव्हाइस वापरण्यासाठी, कृपया सर्वप्रथम Android अनलॉक करा आणि त्यानंतर USB डिव्हाइस वापरण्यासाठी ते पुन्हा घाला."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"संशयास्पद USB ॲक्टिव्हिटी"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB डेटा सिग्नल बंद करण्यात आला आहे."</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index f9aeec485295..5cac65d3077c 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Nyahsemat"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Nyahsemat <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Maklumat apl"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Sasaran perkongsian langsung"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Cadangan apl"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Senarai apl"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Memulakan tunjuk cara…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Menetapkan semula peranti…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Tengah"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel tetapan jenis autoklik"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Klik kiri"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Klik kanan"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Klik dua kali"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Seret"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Tatal"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Jeda"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Kedudukan"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikasi"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Cap jari anda tidak dapat dicam lagi. Sediakan semula Buka Kunci Cap Jari."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Peranti USB dipalamkan apabila dikunci"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Peranti USB dipalamkan apabila Android dikunci. Untuk menggunakan peranti, sila buka kunci Android dahulu, kemudian masukkan semula peranti USB untuk menggunakan peranti itu."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Aktiviti USB yang mencurigakan"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Isyarat data USB telah dilumpuhkan."</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 293b316efa00..10bcd1b75d9c 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"ဖြုတ်ပါ"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> ကို ပင်ဖြုတ်ရန်"</string>
<string name="app_info" msgid="6113278084877079851">"အက်ပ်အချက်အလက်"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"တိုက်ရိုက်မျှဝေသည့် ပစ်မှတ်များ"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"အက်ပ်အကြံပြုချက်များ"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"အက်ပ်စာရင်း"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"သရုပ်ပြချက်ကို စတင်နေသည်…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"စက်ပစ္စည်းကို ပြန်လည်သတ်မှတ်နေသည်…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ဘယ်"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ညာ"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad အလယ်"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"အော်တိုနှိပ်ခြင်း အမျိုးအစား ဆက်တင်အကန့်"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ဘယ်ကလစ်"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ခဏရပ်ရန်"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"နေရာ"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>-"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ပုံပို့ထားသည်"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"အပလီကေးရှင်းများ"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"သင့်လက်ဗွေများကို မသိရှိနိုင်တော့ပါ။ ‘လက်ဗွေသုံး လော့ခ်ဖွင့်ခြင်း’ ထပ်မံစနစ်ထည့်သွင်းပါ။"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"လော့ခ်ချထားချိန်တွင် USB စက်ကို ပလတ်တပ်ထားခြင်း"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android လော့ခ်ချထားချိန်တွင် USB စက်ကို ပလတ်တပ်ထားသည်။ စက်သုံးရန်အတွက် Android ကို အရင်ဖွင့်ပြီး USB စက်ပြန်ထည့်ကာ သုံးပါ။"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"သံသယဖြစ်ဖွယ် USB လုပ်ဆောင်ချက်"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB ဒေတာအချက်ပြမှုကို ပိတ်လိုက်ပါပြီ။"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index a79ff1e4d7bf..800f118baea5 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Løsne"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Løsne <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Info om appen"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Direkte delingsmål"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Appforslag"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Appliste"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Starter demo …"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Tilbakestiller enheten …"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Venstre på styrepilene"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Høyre på styrepilene"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Midt på styrepilene"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Innstillingspanel for type autoklikk"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Venstreklikk"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Sett på pause"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Plassér"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"har sendt et bilde"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Apper"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Fingeravtrykkene dine kan ikke gjenkjennes lenger. Konfigurer opplåsing med fingeravtrykk på nytt."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-enheten er koblet til når den er låst"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-enheten er koblet til når Android er låst. Før du kan bruke enheten, må du låse opp Android og så sette inn USB-enheten på nytt."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Mistenkelig USB-aktivitet"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB-datasignalet er slått av."</string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 3f24b2773404..ce0c67ebd8a2 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -351,7 +351,7 @@
<string name="permgroupdesc_phone" msgid="270048070781478204">"फोन कलहरू गर्नुहोस् र व्यवस्थापन गर्नुहोस्"</string>
<string name="permgrouplab_sensors" msgid="9134046949784064495">"बडी सेन्सरहरू"</string>
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"तपाईंको महत्त्वपूर्ण संकेत बारे सेन्सर डेटा पहुँच गर्नुहोस्"</string>
- <string name="permgrouplab_notifications" msgid="5472972361980668884">"सूचनाहरू"</string>
+ <string name="permgrouplab_notifications" msgid="5472972361980668884">"नोटिफिकेसनहरू"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"सूचनाहरू देखाउनुहोस्"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"विन्डो सामग्रीको पुनःबहाली गर्नुहोस्।"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"तपाईँको अन्तरक्रिया भइरहेको विन्डोको सामग्रीको निरीक्षण गर्नुहोस्।"</string>
@@ -877,7 +877,7 @@
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्क्रिन लकका केही सुविधा असक्षम पार्ने"</string>
<string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"स्क्रिन लकका केही सुविधाहरूको प्रयोगमा रोक लगाउन।"</string>
<string-array name="phoneTypes">
- <item msgid="8996339953292723951">"गृह"</item>
+ <item msgid="8996339953292723951">"घर"</item>
<item msgid="7740243458912727194">"मोबाइल"</item>
<item msgid="8526146065496663766">"काम गर्नुहोस्"</item>
<item msgid="8150904584178569699">"कार्य फ्याक्स"</item>
@@ -887,19 +887,19 @@
<item msgid="6216981255272016212">" कस्टम"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="7786349763648997741">"गृह"</item>
+ <item msgid="7786349763648997741">"घर"</item>
<item msgid="435564470865989199">"काम"</item>
<item msgid="4199433197875490373">"अन्य"</item>
<item msgid="3233938986670468328">" कस्टम"</item>
</string-array>
<string-array name="postalAddressTypes">
- <item msgid="3861463339764243038">"गृह"</item>
+ <item msgid="3861463339764243038">"घर"</item>
<item msgid="5472578890164979109">"काम"</item>
<item msgid="5718921296646594739">"अन्य"</item>
<item msgid="5523122236731783179">" कस्टम"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="588088543406993772">"गृह"</item>
+ <item msgid="588088543406993772">"घर"</item>
<item msgid="5503060422020476757">"काम"</item>
<item msgid="2530391194653760297">"अन्य"</item>
<item msgid="7640927178025203330">" कस्टम"</item>
@@ -920,7 +920,7 @@
<item msgid="8293711853624033835">"Jabber"</item>
</string-array>
<string name="phoneTypeCustom" msgid="5120365721260686814">" कस्टम"</string>
- <string name="phoneTypeHome" msgid="3880132427643623588">"गृह"</string>
+ <string name="phoneTypeHome" msgid="3880132427643623588">"घर"</string>
<string name="phoneTypeMobile" msgid="1178852541462086735">"मोबाइल"</string>
<string name="phoneTypeWork" msgid="6604967163358864607">"काम"</string>
<string name="phoneTypeFaxWork" msgid="6757519896109439123">"कार्य फ्याक्स"</string>
@@ -945,16 +945,16 @@
<string name="eventTypeAnniversary" msgid="4684702412407916888">"वार्षिक समारोह"</string>
<string name="eventTypeOther" msgid="530671238533887997">"अन्य"</string>
<string name="emailTypeCustom" msgid="1809435350482181786">" कस्टम"</string>
- <string name="emailTypeHome" msgid="1597116303154775999">"गृह"</string>
+ <string name="emailTypeHome" msgid="1597116303154775999">"घर"</string>
<string name="emailTypeWork" msgid="2020095414401882111">"काम"</string>
<string name="emailTypeOther" msgid="5131130857030897465">"अन्य"</string>
<string name="emailTypeMobile" msgid="787155077375364230">"मोबाइल"</string>
<string name="postalTypeCustom" msgid="5645590470242939129">" कस्टम"</string>
- <string name="postalTypeHome" msgid="7562272480949727912">"गृह"</string>
+ <string name="postalTypeHome" msgid="7562272480949727912">"घर"</string>
<string name="postalTypeWork" msgid="8553425424652012826">"काम"</string>
<string name="postalTypeOther" msgid="7094245413678857420">"अन्य"</string>
<string name="imTypeCustom" msgid="5653384545085765570">" कस्टम"</string>
- <string name="imTypeHome" msgid="6996507981044278216">"गृह"</string>
+ <string name="imTypeHome" msgid="6996507981044278216">"घर"</string>
<string name="imTypeWork" msgid="2099668940169903123">"काम"</string>
<string name="imTypeOther" msgid="8068447383276219810">"अन्य"</string>
<string name="imProtocolCustom" msgid="4437878287653764692">" कस्टम"</string>
@@ -986,7 +986,7 @@
<string name="relationTypeSister" msgid="3721676005094140671">"बहिनी"</string>
<string name="relationTypeSpouse" msgid="6916682664436031703">"पति-पत्नी"</string>
<string name="sipAddressTypeCustom" msgid="6283889809842649336">" कस्टम"</string>
- <string name="sipAddressTypeHome" msgid="5918441930656878367">"गृह"</string>
+ <string name="sipAddressTypeHome" msgid="5918441930656878367">"घर"</string>
<string name="sipAddressTypeWork" msgid="7873967986701216770">"काम गर्नुहोस्"</string>
<string name="sipAddressTypeOther" msgid="6317012577345187275">"अन्य"</string>
<string name="quick_contacts_not_available" msgid="1262709196045052223">"यो सम्पर्क हेर्न कुनै पनि एप फेला परेन।"</string>
@@ -1408,7 +1408,7 @@
<string name="install_carrier_app_notification_button" msgid="6257740533102594290">"एप डाउनलोड गर्नुहोस्"</string>
<string name="carrier_app_notification_title" msgid="5815477368072060250">"नयाँ SIM घुसाइयो"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"यसलाई सेटअप गर्न ट्याप गर्नुहोस्"</string>
- <string name="time_zone_change_notification_title" msgid="5232503069219193218">"तपाईंको प्रामाणिक समय परिवर्तन गरिएको छ"</string>
+ <string name="time_zone_change_notification_title" msgid="5232503069219193218">"तपाईंको प्रामाणिक समय परिवर्तन भएको छ"</string>
<string name="time_zone_change_notification_body" msgid="6135793674904665585">"तपाईं अहिले <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) मा हुनुहुन्छ"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"समय मिलाउनुहोस्"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"मिति मिलाउनुहोस्"</string>
@@ -1758,7 +1758,7 @@
<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>
+ <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"अन छ"</string>
<string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"निष्क्रिय"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> लाई तपाईंको डिभाइस पूर्ण रूपमा नियन्त्रण गर्न दिने हो?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"एक्सेसिबिलिटीसम्बन्धी आवश्यकतामा सहयोग गर्ने एपको पूर्ण नियन्त्रण गर्न दिनु उपयुक्त हुन्छ तर अधिकांश एपका हकमा यस्तो नियन्त्रण उपयुक्त हुँदैन।"</string>
@@ -2188,12 +2188,12 @@
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"यस सूचनालाई कम महत्त्वपूर्ण ठानी यसका लागि साइलेन्ट मोड सेट गरिएको छ। प्रतिक्रिया दिन ट्याप गर्नुहोस्।"</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"यस सूचनालाई धेरै महत्त्वपूर्ण सूचनाका रूपमा सेट गरिएको छ। प्रतिक्रिया दिन ट्याप गर्नुहोस्।"</string>
<string name="notification_feedback_indicator_demoted" msgid="8880309924296450875">"यस सूचनालाई कम महत्त्वपूर्ण सूचनाका रूपमा सेट गरिएको छ। प्रतिक्रिया दिन ट्याप गर्नुहोस्।"</string>
- <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"परिष्कृत सूचनाहरू"</string>
- <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"अब परिष्कृत सूचनाहरू नामक सुविधाले कारबाही तथा जवाफहरूसम्बन्धी सुझाव देखाउँछ। Android को एड्याप्टिभ सूचनाहरू नामक सुविधाले अब उप्रान्त काम गर्दैन।"</string>
+ <string name="nas_upgrade_notification_title" msgid="8436359459300146555">"परिष्कृत नोटिफिकेसनहरू"</string>
+ <string name="nas_upgrade_notification_content" msgid="5157550369837103337">"अब परिष्कृत नोटिफिकेसनहरू नामक सुविधाले कारबाही तथा जवाफहरूसम्बन्धी सुझाव देखाउँछ। Android को एड्याप्टिभ नोटिफिकेसनहरू नामक सुविधाले अब उप्रान्त काम गर्दैन।"</string>
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ठिक छ"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"अफ गर्नुहोस्"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"थप जान्नुहोस्"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android १२ मा Android को एड्याप्टिभ सूचनाहरू नामक सुविधालाई परिष्कृत सूचनाहरू नामक सुविधाले प्रतिस्थापन गरेको छ। यो सुविधाले कारबाही तथा जवाफसम्बन्धी सुझाव देखाउँछ र तपाईंका सूचनाहरू व्यवस्थित गर्छ।\n\nपरिष्कृत सूचनाहरू नामक सुविधाले सूचनामा उल्लिखित सम्पर्क व्यक्तिको नाम र म्यासेज जस्ता व्यक्तिगत जानकारीलगायतका सामग्री हेर्न तथा प्रयोग गर्न सक्छ। यो सुविधाले फोन उठाउने तथा \'बाधा नपुऱ्याउनुहोस्\' मोड नियन्त्रण गर्ने कार्यसहित सूचनाहरू हटाउने वा सूचनाहरूको जवाफ दिने कार्य पनि गर्न सक्छ।"</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android १२ मा Android को एड्याप्टिभ नोटिफिकेसनहरू नामक सुविधालाई परिष्कृत नोटिफिकेसनहरू नामक सुविधाले प्रतिस्थापन गरेको छ। यो सुविधाले कारबाही तथा जवाफसम्बन्धी सुझाव देखाउँछ र तपाईंका नोटिफिकेसनहरू व्यवस्थित गर्छ।\n\nपरिष्कृत नोटिफिकेसनहरू नामक सुविधाले नोटिफिकेसनमा उल्लिखित सम्पर्क व्यक्तिको नाम र म्यासेज जस्ता व्यक्तिगत जानकारीलगायतका सामग्री हेर्न तथा प्रयोग गर्न सक्छ। यो सुविधाले फोन उठाउने तथा \'बाधा नपुऱ्याउनुहोस्\' मोड नियन्त्रण गर्ने कार्यसहित नोटिफिकेसनहरू हटाउने वा नोटिफिकेसनहरूको जवाफ दिने कार्य पनि गर्न सक्छ।"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"दिनचर्या मोडको जानकारीमूलक सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"ब्याट्री सेभर अन गरिएको छ"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"ब्याट्रीको आयु बढाउन ब्याट्रीको खपत कम गरिँदै छ"</string>
@@ -2231,7 +2231,7 @@
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"होम"</string>
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"पछाडि फर्कनुहोस्"</string>
<string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"हालसालैका एपहरू"</string>
- <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"सूचनाहरू"</string>
+ <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"नोटिफिकेसनहरू"</string>
<string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"द्रुत सेटिङहरू"</string>
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"पावर संवाद"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"लक स्क्रिन"</string>
@@ -2248,14 +2248,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad को बायाँको बटन"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad को दायाँको बटन"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad को बिचको बटन"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"अटोक्लिकको प्रकारसम्बन्धी सेटिङको प्यानल"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"बायाँ क्लिक गर्नुहोस्"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"पज गर्नुहोस्"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"स्थिति"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"फोटो पठाइयो"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 38bcffab7c33..34666415d87a 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Losmaken"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> losmaken"</string>
<string name="app_info" msgid="6113278084877079851">"App-info"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Doelen voor direct delen"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"App-suggesties"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"App-lijst"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demo starten…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Apparaat resetten…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad midden"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Deelvenster met instellingen voor het type automatisch klikken"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Klikken met de linkermuisknop"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Klikken met de rechtermuisknop"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dubbelklikken"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Slepen"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scrollen"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauzeren"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Positie"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Kaarten"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Apps"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Je vingerafdrukken worden niet meer herkend. Stel Ontgrendelen met vingerafdruk opnieuw in."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-apparaat aangesloten terwijl vergrendeld"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Het USB-apparaat is aangesloten terwijl Android is vergrendeld. Als je het apparaat wilt gebruiken, ontgrendel je eerst Android en plaats je het USB-apparaat opnieuw om het te gebruiken."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Verdachte USB-activiteit"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB-gegevenssignaal is uitgezet."</string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index e99010f02be0..418231f5e9b2 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2042,7 +2042,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"ଆପ୍‌ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"ବର୍ତ୍ତମାନ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ। ଏହା <xliff:g id="APP_NAME_1">%2$s</xliff:g> ଦ୍ଵାରା ପରିଚାଳିତ ହେଉଛି।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
- <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ଆପ୍ ଅନପଜ୍ କରନ୍ତୁ"</string>
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ଆପ ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="work_mode_off_title" msgid="6367463960165135829">"ୱାର୍କ ଆପ୍ସକୁ ପୁଣି ଚାଲୁ କରିବେ?"</string>
<string name="work_mode_turn_on" msgid="5316648862401307800">"ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ଜରୁରୀକାଳୀନ"</string>
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"ଅନପିନ୍ କରନ୍ତୁ"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g>ରେ ଅନ୍‌ପିନ୍ କରନ୍ତୁ"</string>
<string name="app_info" msgid="6113278084877079851">"ଆପ୍‍ ସୂଚନା"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"ଡାଇରେକ୍ଟ ସେୟାର ଟାର୍ଗେଟ"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"ଆପ ପରାମର୍ଶ"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"ଆପ ତାଲିକା"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ଡେମୋ ଆରମ୍ଭ କରାଯାଉଛି…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"ଡିଭାଇସ୍‍କୁ ରିସେଟ୍‍ କରାଯାଉଛି…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ବାମ"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ଡାହାଣ"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad କେନ୍ଦ୍ର"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ଅଟୋକ୍ଲିକ ପ୍ରକାର ସେଟିଂସ ପେନେଲ"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ବାମ ବଟନ କ୍ଲିକ କରନ୍ତୁ"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ବିରତ କରନ୍ତୁ"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ସ୍ଥିତି"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ଏକ ଛବି ପଠାଯାଇଛି"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"ଆପ୍ଲିକେସନ"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"ଆପଣଙ୍କ ଟିପଚିହ୍ନକୁ ଆଉ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ। ଫିଙ୍ଗରପ୍ରିଣ୍ଟ ଅନଲକ ପୁଣି ସେଟ ଅପ କରନ୍ତୁ।"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"ଲକ ଥିବା ସମୟରେ USB ଡିଭାଇସ ପ୍ଲଗ ଇନ ହୋଇଛି"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android ଲକ ଥିବାବେଳେ USB ଡିଭାଇସ ପ୍ଲଗ ଇନ ହୋଇଥାଏ। ଡିଭାଇସ ବ୍ୟବହାର କରିବାକୁ, ଦୟାକରି ପ୍ରଥମେ Android ଅନଲକ କରନ୍ତୁ ଏବଂ ତାପରେ ଏହାକୁ ବ୍ୟବହାର କରିବାକୁ USB ଡିଭାଇସ ପୁଣି ଭର୍ତ୍ତି କରନ୍ତୁ।"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"ସନ୍ଦେହଜନକ USB କାର୍ଯ୍ୟକଳାପ"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB ଡାଟା ସିଗନାଲକୁ ଅକ୍ଷମ କରାଯାଇଛି।"</string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 63765aa11e78..26769a637388 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"ਅਨਪਿੰਨ ਕਰੋ"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> ਨੂੰ ਅਨਪਿੰਨ ਕਰੋ"</string>
<string name="app_info" msgid="6113278084877079851">"ਐਪ ਜਾਣਕਾਰੀ"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"ਸਿੱਧੇ ਤੌਰ \'ਤੇ ਸਾਂਝਾ ਕਰਨ ਲਈ ਟਾਰਗੇਟ ਗਰੁੱਪ"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"ਐਪ ਸੁਝਾਅ"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"ਐਪ ਸੂਚੀ"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ਡੈਮੋ ਚਾਲੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"ਡੀਵਾਈਸ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ਦਾ ਵਿਚਕਾਰਲਾ ਬਟਨ"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ਸਵੈ-ਕਲਿੱਕ ਟਾਈਪ ਸੈਟਿੰਗ ਪੈਨਲ"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ਖੱਬਾ-ਕਲਿੱਕ ਦਬਾਓ"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"ਸੱਜਾ-ਕਲਿੱਕ ਦਬਾਓ"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ਡਬਲ ਕਲਿੱਕ ਕਰੋ"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ਘਸੀਟੋ"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ਸਕ੍ਰੋਲ ਕਰੋ"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ਰੋਕੋ"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"ਸਥਿਤੀ"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"ਐਪਲੀਕੇਸ਼ਨਾਂ"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"ਤੁਹਾਡੇ ਫਿੰਗਰਪ੍ਰਿੰਟਾਂ ਦੀ ਹੁਣ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਫਿੰਗਰਪ੍ਰਿੰਟ ਅਣਲਾਕ ਦਾ ਦੁਬਾਰਾ ਸੈੱਟਅੱਪ ਕਰੋ।"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"ਲਾਕ ਹੋਣ \'ਤੇ USB ਡੀਵਾਈਸ ਨੂੰ ਪਲੱਗ-ਇਨ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android ਲਾਕ ਹੋਣ \'ਤੇ USB ਡੀਵਾਈਸ ਨੂੰ ਪਲੱਗ-ਇਨ ਕੀਤਾ ਗਿਆ। ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ, ਕਿਰਪਾ ਕਰਕੇ ਪਹਿਲਾਂ Android ਨੂੰ ਅਣਲਾਕ ਕਰੋ ਅਤੇ ਫਿਰ USB ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਉਸਨੂੰ ਦੁਬਾਰਾ ਲਗਾਓ।"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"ਸ਼ੱਕੀ USB ਸਰਗਰਮੀ"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB ਡਾਟਾ ਸਿਗਨਲ ਬੰਦ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ।"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 372608d3af15..e091700ed9d0 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2090,12 +2090,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Odepnij"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Odepnij: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"O aplikacji"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Odbiorcy udostępniania bezpośredniego"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Sugestie aplikacji"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista aplikacji"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Uruchamiam tryb demo…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Resetuję urządzenie…"</string>
@@ -2250,14 +2247,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad – w lewo"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad – w prawo"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad – środek"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel ustawień typu automatycznego kliknięcia"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Kliknięcie lewym przyciskiem"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Wstrzymaj"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozycja"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"wysłano obraz"</string>
@@ -2532,12 +2533,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Mapy"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikacje"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Nie można już rozpoznać Twoich odcisków palców. Skonfiguruj ponownie odblokowywanie odciskiem palca."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Podłączono urządzenie USB przy zablokowanym urządzeniu"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Podłączono urządzenie USB, gdy Android był zablokowany. Aby używać urządzenia USB, najpierw odblokuj Androida, a potem podłącz je ponownie."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Podejrzana aktywność przez USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Sygnał danych z urządzenia USB został wyłączony."</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index dc5275918233..06b43cbd0699 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Liberar guia"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Liberar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informações do app"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Destinos de compartilhamento direto"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Sugestões de apps"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista de apps"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Iniciando demonstração…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Redefinindo dispositivo…"</string>
@@ -2249,14 +2246,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Botão direcional: para a esquerda"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Botão direcional: para a direita"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Botão direcional: centro"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Painel de configurações do tipo de clique automático"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Botão esquerdo"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Clicar com o botão direito do mouse"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Clicar duas vezes"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Arrastar"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rolar"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posição"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string>
@@ -2531,12 +2528,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Mapas"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Apps"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"As impressões digitais não são mais reconhecidas. Configure o Desbloqueio por impressão digital de novo."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"O dispositivo USB foi conectado com o Android bloqueado"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"O dispositivo USB foi conectado com o Android bloqueado. Para usá-lo, primeiro desbloqueie o Android e, em seguida, reconecte o dispositivo USB."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Atividade suspeita do USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"O indicador de dados USB foi desativado."</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 1418a0b0aac2..f48c3260534a 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Soltar"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Soltar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Info. da app"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Segmentações de partilha direta"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Sugestões de apps"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista de apps"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"A iniciar a demonstração…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"A repor o dispositivo…"</string>
@@ -2251,6 +2248,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Teclado direcional: centrar"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Painel de definições do tipo de clique automático"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clicar com o botão esquerdo do rato"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Clicar com o botão direito do rato"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Clicar duas vezes"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Arrastar"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Deslocar"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posição"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string>
@@ -2527,12 +2528,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplicações"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Já não é possível reconhecer as suas impressões digitais. Configure o Desbloqueio por impressão digital novamente."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Dispositivo USB ligado quando bloqueado"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"O dispositivo USB está ligado quando o Android está bloqueado. Para usar o dispositivo, desbloqueie primeiro o Android e, de seguida, volte a inserir o dispositivo USB para o usar."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Atividade USB suspeita"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"O sinal de dados USB foi desativado."</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index dc5275918233..06b43cbd0699 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Liberar guia"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Liberar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informações do app"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Destinos de compartilhamento direto"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Sugestões de apps"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista de apps"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Iniciando demonstração…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Redefinindo dispositivo…"</string>
@@ -2249,14 +2246,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Botão direcional: para a esquerda"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Botão direcional: para a direita"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Botão direcional: centro"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Painel de configurações do tipo de clique automático"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Botão esquerdo"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Clicar com o botão direito do mouse"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Clicar duas vezes"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Arrastar"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rolar"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posição"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string>
@@ -2531,12 +2528,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Mapas"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Apps"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"As impressões digitais não são mais reconhecidas. Configure o Desbloqueio por impressão digital de novo."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"O dispositivo USB foi conectado com o Android bloqueado"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"O dispositivo USB foi conectado com o Android bloqueado. Para usá-lo, primeiro desbloqueie o Android e, em seguida, reconecte o dispositivo USB."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Atividade suspeita do USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"O indicador de dados USB foi desativado."</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 75369415e322..73f532a7d633 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Anulează fixarea"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Anulează fixarea pentru <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informații despre aplicație"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Destinații de distribuire directă"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Sugestii de aplicații"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista cu aplicații"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Se pornește demonstrația…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Se resetează dispozitivul…"</string>
@@ -2249,14 +2246,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad stânga"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad dreapta"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centru"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panoul de setări pentru clicul automat"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic stânga"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Întrerupe"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Poziție"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a trimis o imagine"</string>
@@ -2531,12 +2532,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplicații"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"E posibil ca amprentele tale să nu mai fie recunoscute. Configurează din nou Deblocarea cu amprenta."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Dispozitiv USB conectat când Android este blocat"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Dispozitivul USB este conectat când dispozitivul Android este blocat. Pentru a folosi dispozitivul, deblochează mai întâi dispozitivul Android, apoi reconectează dispozitivul USB pentru a-l folosi."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Activitate suspectă a dispozitivului USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Semnalul de date USB a fost dezactivat."</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index f35392f3911a..e0e08072482a 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2090,12 +2090,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Открепить"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Открепить приложение \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string>
<string name="app_info" msgid="6113278084877079851">"О приложении"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Получатели Direct Share"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Рекомендуемые приложения"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Список приложений"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Запуск деморежима…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Сброс данных…"</string>
@@ -2252,6 +2249,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad – по центру"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Панель настроек типа автонажатия"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Нажать левую кнопку"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Нажать правую кнопку"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Нажать дважды"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Перетащить"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Прокрутить"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Приостановить"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Положение"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string>
@@ -2528,12 +2529,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Карты"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Приложения"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Ваши отпечатки больше не распознаются. Настройте разблокировку по отпечатку пальца снова."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Разблокируйте экран"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Устройство Android заблокировано. Чтобы использовать USB-устройство, переподключите его после разблокировки экрана."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Обнаружено подозрительное USB-устройство"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Передача данных по USB отключена."</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index d21df4a7f702..45dd5df8f83f 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -2248,14 +2248,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad වම"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad දකුණ"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad මැද"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ස්වයං ක්ලික් ආකාර සැකසීම් පැනලය"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"වම්පස ක්ලිකය"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"විරාම කරන්න"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ස්ථානය"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"රූපයක් එව්වා"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 56fa73cba3fd..d67597821b2d 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -75,7 +75,7 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"V predvolenom nastavení nie je identifikácia volajúceho obmedzená. Ďalší hovor: Bez obmedzenia"</string>
<string name="page_size_compat_apk_warning" msgid="2982396798449041224">"Táto aplikácia nie je kompatibilná s režimom 16 kB. Nepodarilo sa skontrolovať zarovnanie súboru APK. Táto aplikácia bude spustená v režime kompatibilnom s veľkosťou stránky. Ak chcete dosiahnuť najlepšiu kompatibilitu, znova skompilujte aplikáciu s podporou 16 kB. Viac sa dozviete na &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;."</string>
<string name="page_size_compat_elf_warning" msgid="6753874059564812651">"Táto aplikácia nie je kompatibilná s režimom 16 kB. Nepodarilo sa skontrolovať zarovnanie formátu ELF. Táto aplikácia bude spustená v režime kompatibilnom s veľkosťou stránky. Ak chcete dosiahnuť najlepšiu kompatibilitu, znova skompilujte aplikáciu s podporou 16 kB. Viac sa dozviete na &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;."</string>
- <string name="page_size_compat_apk_and_elf_warning" msgid="7628675779500605390">"Táto aplikácia nie je kompatibilná s režimom 16 kB. Nepodarilo sa skontrolovať zarovnanie súboru APK a formátu ELF. Táto aplikácia bude spustená v režime kompatibilnom s veľkosťou stránky. Ak chcete dosiahnuť najlepšiu kompatibilitu, znova skompilujte aplikáciu s podporou 16 kB. Viac sa dozviete na &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;."</string>
+ <string name="page_size_compat_apk_and_elf_warning" msgid="7628675779500605390">"Táto aplikácia nie je kompatibilná s 16 kB stránkovaním. Kontrola zarovnania v súboroch APK a ELF sa nepodarila. Aplikácia pobeží v režime kompatibility s veľkosťou stránky. Pre optimálnu kompatibilitu aplikáciu prekompilujte s podporou 16 kB stránkovania. Viac sa dozviete na &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Služba nie je poskytovaná."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Nemôžete meniť nastavenie identifikácie volajúcich."</string>
<string name="auto_data_switch_title" msgid="3286350716870518297">"Dátové pripojenie bolo prepnuté na operátora <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
@@ -2090,12 +2090,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Uvoľniť"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Odopnúť <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informácie o aplikácii"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Ciele priameho zdieľania"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Návrhy aplikácií"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Zoznam aplikácií"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Spúšťa sa ukážka…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Resetuje sa zariadenie…"</string>
@@ -2252,6 +2249,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Stlačiť stredné tlačidlo krížového ovládača"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel nastavení typu automatického kliknutia"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Kliknutie ľavým tlačidlom"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Kliknúť pravým tlačidlom"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dvakrát kliknúť"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Presunúť"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Posúvať"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pozastaviť"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozícia"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string>
@@ -2528,12 +2529,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Mapy"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikácie"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Vaše odtlačky prstov sa už nedajú rozpoznať. Znova nastavte odomknutie odtlačkom prsta."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Zariadenie USB bolo pripojené počas uzamknutia"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Zariadenie USB bolo pripojené, keď bolo zariadenie s Androidom uzamknuté. Ak chcete dané zariadenie používať, najprv odomknite zariadenie s Androidom a potom znova vložte zariadenie USB."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Podozrivá aktivita cez USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Dátový signál cez USB bol deaktivovaný."</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index f44f1e798068..0136f5f8311a 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -278,7 +278,7 @@
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Celotno poročilo"</string>
<string name="bugreport_option_full_summary" msgid="1975130009258435885">"To možnost uporabite za najmanj motenj sistema, če je naprava neodzivna ali prepočasna oziroma ko potrebujete vse razdelke poročila. Ne omogoča vnosa več podrobnosti ali snemanja dodatnih posnetkov zaslona."</string>
<string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Posnetek zaslona za poročilo o napakah bo narejen čez # sekundo.}one{Posnetek zaslona za poročilo o napakah bo narejen čez # sekundo.}two{Posnetek zaslona za poročilo o napakah bo narejen čez # sekundi.}few{Posnetek zaslona za poročilo o napakah bo narejen čez # sekunde.}other{Posnetek zaslona za poročilo o napakah bo narejen čez # sekund.}}"</string>
- <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Posnetek zaslona s poročilom o napakah je izdelan"</string>
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Posnetek zaslona s poročilom je ustvarjen"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Izdelava posnetka zaslona s poročilom o napakah ni uspela"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tihi način"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvok je IZKLOPLJEN"</string>
@@ -2090,12 +2090,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Odpenjanje"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Odpni aplikacijo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Podatki o aplikacijah"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Naslovniki neposrednega deljenja"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Predlagane aplikacije"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Seznam aplikacij"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Začenjanje predstavitve …"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Ponastavljanje naprave …"</string>
@@ -2252,6 +2249,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Smerni gumb sredina"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Podokno z nastavitvami vrste samodejnega klika"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Levi klik"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Desni klik"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dvoklik"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Vlečenje"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Drsenje"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Začasna zaustavitev"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Položaj"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string>
@@ -2528,12 +2529,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Zemljevidi"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikacije"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Vaših prstnih odtisov ni več mogoče prepoznati. Znova nastavite odklepanje s prstnim odtisom."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Naprava USB je bila priključena pri zaklenjenem Androidu"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Naprava USB je bila priključena pri zaklenjenem Androidu. Če želite uporabljati napravo, najprej odklenite Android in nato znova vstavite napravo USB, da jo boste lahko uporabljali."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Sumljiva dejavnost USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Podatkovni signal USB je bil onemogočen."</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 3739b53b32ac..37aa8bf8108f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Zhgozhdo"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Zhgozhdoje <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Informacioni mbi aplikacionin"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Objektivat e ndarjes së drejtpërdrejtë"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Aplikacionet e sugjeruara"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Lista e aplikacioneve"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Po nis demonstrimin..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Po rivendos pajisjen…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Majtas në bllokun e drejtimit"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Djathtas në bllokun e drejtimit"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Qendra e bllokut të drejtimit"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Paneli i cilësimeve për llojin e klikimit automatik"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Klikimi majtas"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Vendos në pauzë"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicioni"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"dërgoi një imazh"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikacionet"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Gjurmët e tua të gishtave nuk mund të njihen më. Konfiguro përsëri \"Shkyçjen me gjurmën e gishtit\"."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Pajisja USB është e futur kur është e kyçur"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Pajisja USB është e futur kur Android është i kyçur. Për ta përdorur pajisjen, shkyç fillimisht Android dhe më pas fut përsëri pajisjen USB për ta përdorur."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Aktivitet i dyshimtë i USB-së"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Sinjali i të dhënave të USB-së është çaktivizuar."</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 009c27bcbb25..a4f0e556a7c7 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2089,12 +2089,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Откачи"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Откачи апликацију <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Информације о апликацији"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Циљеви директног дељења"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Предлози апликација"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Листа апликација"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Покрећемо демонстрацију..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Ресетујемо уређај..."</string>
@@ -2251,6 +2248,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"центар на D-pad-у"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Окно са подешавањима типа аутоматског клика"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Леви клик"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Кликните десним тастером"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Двапут кликните"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Превуците"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Скролујте"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Паузирај"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Позиција"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string>
@@ -2527,12 +2528,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Мапе"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Апликације"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Отисци прстију више не могу да се препознају. Поново подесите откључавање отиском прста."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB уређај је прикључен када је Android закључан"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB уређај је прикључен када је Android закључан. Да бисте користили уређај, прво откључајте Android, па поново убаците USB уређај да бисте га користили."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Сумњива USB активност"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Сигнал за пренос података са USB-а је онемогућен."</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 442763ae3188..e56097f06120 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Lossa"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Lossa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Appinformation"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Personer/grupper att dela direkt med"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Appförslag"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Applista"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demo startas …"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Enheten återställs …"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Styrkors, vänster"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Styrkors, höger"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Styrkors, mitten"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Inställningspanel för typ av automatiskt klick"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Vänsterklick"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausa"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"har skickat en bild"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Appar"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Det går inte längre att känna igen dina fingeravtryck. Ställ in fingeravtryckslås igen."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-enhet ansluten när enheten är låst"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-enheten är ansluten när Android är låst. Om du vill använda enheten måste du först låsa upp Android och sedan sätta i USB-enheten igen."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Misstänkt USB-aktivitet"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB-datasignalen har inaktiverats."</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8153eb02d625..03a581a362ba 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Bandua"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Bandua <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Maelezo ya programu"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Chaguo za kutuma maudhui moja kwa moja"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Mapendekezo ya programu"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Orodha ya programu"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Inaanzisha onyesho..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Inaweka upya kifaa..."</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Kitufe cha kushoto cha Dpad"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Kitufe cha kulia cha Dpad"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Kitufe cha katikati cha Dpad"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Kidirisha cha mipangilio ya aina ya kubofya kiotomatiki"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Bofya kushoto"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Sitisha"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Nafasi"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"alituma picha"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Ramani"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Programu"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Alama zako za vidole hazitambuliki tena. Weka tena mipangilio ya Kufungua kwa Alama ya Kidole."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Kifaa cha USB kimechomekwa wakati Android imefungwa"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Kifaa cha USB huchomekwa wakati Android imefungwa. Tafadhali fungua kwanza Android kisha uweke upya kifaa cha USB ili ukitumie."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Shughuli za USB za kutilia shaka"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Kiashiria cha data cha USB kimezimwa."</string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 94168418ff4d..16c021e8c807 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"பின்னை அகற்று"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> ஐப் பின் நீக்கு"</string>
<string name="app_info" msgid="6113278084877079851">"ஆப்ஸ் தகவல்"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"நேரடிப் பகிர்வு இலக்குகள்"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"ஆப்ஸ் பரிந்துரைகள்"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"ஆப்ஸ் பட்டியல்"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"டெமோவைத் தொடங்குகிறது…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"சாதனத்தை மீட்டமைக்கிறது…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"இடது திசை காட்டும் பட்டன்"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"வலது திசை காட்டும் பட்டன்"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"மையப் பகுதியைக் காட்டும் பட்டன்"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ஆட்டோ கிளிக் வகை அமைப்புகள் பேனல்"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"இடது கிளிக்"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"இடைநிறுத்து"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"நிலை"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"படம் அனுப்பப்பட்டது"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"ஆப்ஸ்"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"உங்கள் கைரேகைகளை இனி அடையாளம் காண முடியாது. கைரேகை அன்லாக் அம்சத்தை மீண்டும் அமையுங்கள்."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"பூட்டப்பட்டிருக்கும்போது USB சாதனம் செருகப்பட்டது"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android பூட்டப்பட்டிருக்கும்போது USB சாதனம் செருகப்பட்டது. சாதனத்தைப் பயன்படுத்த, முதலில் Androidடைத் திறக்கவும், பின்னர் USB சாதனத்தைப் பயன்படுத்த அதை மீண்டும் செருகவும்."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"சந்தேகத்திற்குரிய USB செயல்பாடு"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB தரவு சிக்னல் முடக்கப்பட்டுள்ளது."</string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 4bb85f72c1d8..c5656187776e 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"అన్‌‌పిన్‌ ‌చేయి"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g>ను అన్‌పిన్ చేయి"</string>
<string name="app_info" msgid="6113278084877079851">"యాప్ సమాచారం"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"టార్గెట్‌లను నేరుగా షేర్ చేయడం"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"యాప్ సూచనలు"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"యాప్ లిస్ట్"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"డెమోను ప్రారంభిస్తోంది..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"పరికరాన్ని రీసెట్ చేస్తోంది..."</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ఎడమవైపున"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad కుడివైపున"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"DPad మధ్యన"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ఆటో-క్లిక్ టైప్ సెట్టింగ్‌ల ప్యానెల్"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ఎడమ క్లిక్"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"పాజ్ చేయండి"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"స్థానం"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్‌లో ఉంచబడింది"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ఇమేజ్‌ను పంపారు"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Maps"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"అప్లికేషన్‌లు"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"మీ వేలిముద్రలను ఇకపై గుర్తించడం సాధ్యం కాదు. వేలిముద్ర అన్‌లాక్‌ను మళ్లీ సెటప్ చేయండి."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"లాక్ చేసి ఉన్నప్పుడు USB డివైజ్ ప్లగ్-ఇన్ అయి ఉంది"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android లాక్ అయినప్పుడు USB డివైజ్ ప్లగ్-ఇన్ చేయబడింది. డివైజ్‌ను ఉపయోగించడానికి, దయచేసి ముందుగా Androidను అన్‌లాక్ చేసి, ఆ తర్వాత, USB డివైజ్‌ను ఉపయోగించడానికి దాన్ని మళ్లీ ఇన్‌సర్ట్ చేయండి."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"USB యాక్టివిటీ అనుమానాస్పదంగా ఉంది"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB డేటా సిగ్నల్ డిజేబుల్ అయింది."</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 26084553817a..f4a3651bc5b7 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"เลิกปักหมุด"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"เลิกปักหมุด <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"ข้อมูลแอป"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"เป้าหมายการแชร์โดยตรง"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"คำแนะนำเกี่ยวกับแอป"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"รายการแอป"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"กำลังเริ่มการสาธิต…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"กำลังรีเซ็ตอุปกรณ์…"</string>
@@ -2250,6 +2247,10 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad กึ่งกลาง"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"แผงการตั้งค่าประเภทการคลิกอัตโนมัติ"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"คลิกซ้าย"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"คลิกขวา"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ดับเบิลคลิก"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ลาก"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"เลื่อน"</string>
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"หยุดชั่วคราว"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"วางตำแหน่ง"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string>
@@ -2526,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"แผนที่"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"แอปพลิเคชัน"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"ระบบจะไม่จดจำลายนิ้วมือของคุณอีกต่อไป ตั้งค่าการปลดล็อกด้วยลายนิ้วมืออีกครั้ง"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"เสียบอุปกรณ์ USB ขณะล็อกอยู่"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"คุณเสียบอุปกรณ์ USB ขณะ Android ล็อกอยู่ หากต้องการใช้อุปกรณ์ โปรดปลดล็อก Android ก่อนแล้วจึงเสียบอุปกรณ์ USB อีกครั้งเพื่อใช้งาน"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"กิจกรรม USB ที่น่าสงสัย"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"สัญญาณข้อมูล USB ปิดอยู่"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 482d7fdbb621..8782970c0aed 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"I-unpin"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"I-unpin ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Impormasyon ng app"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Mga target ng direktang pagbabahagi"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Mga iminumungkahing app"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Listahan ng app"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Sinisimulan ang demo…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Nire-reset ang device…"</string>
@@ -2250,6 +2247,14 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Center"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel ng mga setting ng uri ng autoclick"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Mag-left click"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
+ <skip />
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"I-pause"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posisyon"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string>
@@ -2526,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Mga Mapa"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Mga Application"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Hindi na makikilala ang iyong mga fingerprint. I-set up ulit ang Pag-unlock Gamit ang Fingerprint."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Nakasaksak ang USB device kapag naka-lock"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Nakasaksak ang USB device kapag naka-lock ang Android. Para magamit ang device, paki-unlock muna ang Android at pagkatapos ay isaksak ulit ang USB device para magamit ito."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Kahina-hinalang aktibidad sa USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Na-disable ang data signal ng USB."</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index cb65ad72782d..7048a83b24b2 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Sabitlemeyi kaldır"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> uygulamasının sabitlemesini kaldır"</string>
<string name="app_info" msgid="6113278084877079851">"Uygulama bilgileri"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Doğrudan paylaşım hedefleri"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Önerilen uygulamalar"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Uygulama listesi"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demo başlatılıyor…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Cihaz sıfırlanıyor…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Sol"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Sağ"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Orta"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Otomatik tıklama türü ayarları paneli"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Sol tıklama"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Duraklatma"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Konum"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"bir resim gönderildi"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Haritalar"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Uygulamalar"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Parmak izleriniz artık tanınamıyor. Parmak İzi Kilidi\'ni tekrar kurun."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB cihazı, Android kilitliyken takıldı"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB cihazı, Android kilitliyken takıldı. Cihazı kullanmak için lütfen önce Android\'in kilidini açın, ardından USB cihazını yeniden takın."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Şüpheli USB etkinliği"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB veri sinyali devre dışı bırakıldı."</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 341aff5d70b8..a36699013b33 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2250,14 +2250,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Кнопка \"вліво\" панелі керування"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Кнопка \"вправо\" панелі керування"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Центральна кнопка панелі керування"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Панель налаштувань типу автоматичного натискання"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Натиснути лівою кнопкою миші"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Призупинити"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Змінити позицію"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"надіслано зображення"</string>
@@ -2449,7 +2453,7 @@
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Функція Dual Screen недоступна, оскільки телефон сильно нагрівається"</string>
<string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Функція Dual Screen недоступна"</string>
<string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Функція Dual Screen недоступна, оскільки ввімкнено режим енергозбереження. Її можна вимкнути в налаштуваннях."</string>
- <string name="device_state_notification_settings_button" msgid="691937505741872749">"Перейти до налаштувань"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Відкрити налаштування"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Вимкнути"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Клавіатуру \"<xliff:g id="DEVICE_NAME">%s</xliff:g>\" налаштовано"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Вибрано розкладку клавіатури \"<xliff:g id="LAYOUT_1">%s</xliff:g>\". Натисніть, щоб змінити."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index ec832e67aa2f..b725a126e7cd 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"پن ہٹائیں"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> سے پن ہٹائیں"</string>
<string name="app_info" msgid="6113278084877079851">"ایپ کی معلومات"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"براہ راست اشتراک کے اہداف"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"ایپ کی تجاویز"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"ایپ کی فہرست"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ڈیمو شروع ہو رہا ہے…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"آلہ ری سیٹ ہو رہا ہے…"</string>
@@ -2248,14 +2245,14 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"‏Dpad بائیں کریں"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"‏Dpad دائیں کریں"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"‏Dpad سینٹر"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
- <skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
- <skip />
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"خودکار کلک کی قسم کی ترتیبات کا پینل"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"بایاں کلک کریں"</string>
+ <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"دایاں کلک کریں"</string>
+ <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"دو بار کلک کریں"</string>
+ <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"گھسیٹیں"</string>
+ <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"اسکرول کریں"</string>
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"موقوف کریں"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"پوزیشن"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ایک تصویر بھیجی"</string>
@@ -2530,12 +2527,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"نقشے"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"ایپلیکیشنز"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"آپ کے فنگر پرنٹس کو مزید پہچانا نہیں جا سکتا۔ فنگر پرنٹ اَن لاک کو دوبارہ سیٹ اپ کریں۔"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"‏مقفل ہونے پر USB آلہ پلگ ان ہوتا ہے"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"‏‫Android کے مقفل ہونے پر USB آلہ پلگ ان ہوتا ہے۔ آلہ استعمال کرنے کے لیے، براہ کرم پہلے Android کو غیر مقفل کریں اور پھر اسے استعمال کرنے کے لیے USB آلہ کو دوبارہ داخل کریں۔"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"‏‫USB کی مشکوک سرگرمی"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"‏‫USB ڈیٹا سگنل کو غیر فعال کر دیا گیا ہے۔"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index e764fc293124..a83466937016 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Yechib olish"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Yechib olish: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Ilova haqida"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Direct Share nishonlari"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Ilova takliflari"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Ilovalar roʻyxati"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demo boshlanmoqda…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Qurilma asl holatga qaytarilmoqda…"</string>
@@ -2250,6 +2247,14 @@
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad – markazga"</string>
<string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Avtomatik klik turi sozlamalari paneli"</string>
<string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Chap klik"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
+ <skip />
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
+ <skip />
<string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauza"</string>
<string name="accessibility_autoclick_position" msgid="2933660969907663545">"Joylashuvi"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string>
@@ -2526,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Xaritalar"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Ilovalar"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Barmoq izlaringiz endi tanilmaydi. Barmoq izi bilan ochishni qayta sozlang."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Qulflanganida USB qurilma quvvat manbasiga ulandi"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android qulflanganda USB qurilma quvvat manbasiga ulandi. Qurilmani ishlatish uchun avval Android qulfini oching va keyin uni ishlatish uchun USB qurilmani qayta kiriting."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Shubhali USB faoliyati"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB maʼlumotlar signali faolsizlantirilgan."</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index cd89cfdaa017..c07ff1d0e040 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Bỏ ghim"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Bỏ ghim <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Thông tin ứng dụng"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Mục tiêu chia sẻ trực tiếp"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Ứng dụng đề xuất"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Danh sách ứng dụng"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Đang bắt đầu bản trình diễn..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Đang đặt lại thiết bị..."</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Chuyển sang trái bằng bàn phím di chuyển"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Chuyển sang phải bằng bàn phím di chuyển"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Căn giữa bằng bàn phím di chuyển"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Bảng cài đặt loại tự động nhấp"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Nhấp chuột trái"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Tạm dừng"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Vị trí"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"đã gửi hình ảnh"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Bản đồ"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Ứng dụng"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Hệ thống không nhận dạng được vân tay của bạn. Hãy thiết lập lại tính năng Mở khoá bằng vân tay."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Thiết bị USB được cắm khi thiết bị Android đang khoá"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Thiết bị USB đã được cắm khi thiết bị Android đang khoá. Để sử dụng thiết bị USB, trước tiên, hãy mở khoá thiết bị Android rồi cắm lại thiết bị USB."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Hoạt động đáng ngờ liên quan đến USB"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Tín hiệu dữ liệu qua USB đã bị tắt."</string>
</resources>
diff --git a/core/res/res/values-w192dp/dimens_watch.xml b/core/res/res/values-w192dp/dimens_watch.xml
new file mode 100644
index 000000000000..c6bf767ab6b8
--- /dev/null
+++ b/core/res/res/values-w192dp/dimens_watch.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2025 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>
+ <!-- 16.7% of display size -->
+ <dimen name="base_error_dialog_top_padding">32dp</dimen>
+ <!-- 5.2% of display size -->
+ <dimen name="base_error_dialog_padding">10dp</dimen>
+ <!-- 20.83% of display size -->
+ <dimen name="base_error_dialog_bottom_padding">40dp</dimen>
+
+ <!-- watch's indeterminate progress bar dimens based on the current screen size -->
+ <dimen name="loader_horizontal_min_width_watch">67dp</dimen>
+ <dimen name="loader_horizontal_min_height_watch">15dp</dimen>
+</resources>
diff --git a/core/res/res/values-w204dp-round-watch/dimens_watch.xml b/core/res/res/values-w204dp-round-watch/dimens_watch.xml
new file mode 100644
index 000000000000..3509474c5c2e
--- /dev/null
+++ b/core/res/res/values-w204dp-round-watch/dimens_watch.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2025 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>
+ <!-- watch's indeterminate progress bar dimens based on the current screen size -->
+ <dimen name="loader_horizontal_min_width_watch">70dp</dimen>
+ <dimen name="loader_horizontal_min_height_watch">15dp</dimen>
+</resources>
diff --git a/core/res/res/values-w216dp/dimens_watch.xml b/core/res/res/values-w216dp/dimens_watch.xml
new file mode 100644
index 000000000000..e14ce5e98f55
--- /dev/null
+++ b/core/res/res/values-w216dp/dimens_watch.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ Copyright (C) 2025 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>
+ <!-- watch's indeterminate progress bar dimens based on the current screen size -->
+ <dimen name="loader_horizontal_min_width_watch">72dp</dimen>
+ <dimen name="loader_horizontal_min_height_watch">16dp</dimen>
+</resources> \ No newline at end of file
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/res/layout/input_view.xml b/core/res/res/values-w228dp/dimens_watch.xml
index f2292701e795..3c6265690c3c 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/res/layout/input_view.xml
+++ b/core/res/res/values-w228dp/dimens_watch.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2025 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,9 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/input"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/> \ No newline at end of file
+<resources>
+ <!-- watch's indeterminate progress bar dimens based on the current screen size -->
+ <dimen name="loader_horizontal_min_width">76dp</dimen>
+ <dimen name="loader_horizontal_min_height">14dp</dimen>
+</resources>
diff --git a/core/res/res/values-w240dp/dimens_material.xml b/core/res/res/values-w240dp/dimens_material.xml
index bd26c8bf84df..e30aea46aec7 100644
--- a/core/res/res/values-w240dp/dimens_material.xml
+++ b/core/res/res/values-w240dp/dimens_material.xml
@@ -21,4 +21,8 @@
<dimen name="screen_percentage_12">28.8dp</dimen>
<dimen name="screen_percentage_15">36dp</dimen>
<dimen name="screen_percentage_3646">87.5dp</dimen>
+
+ <!-- watch's indeterminate progress bar dimens based on the current screen size -->
+ <dimen name="progress_indeterminate_horizontal_min_width_watch">80dp</dimen>
+ <dimen name="progress_indeterminate_horizontal_min_height_watch">17dp</dimen>
</resources>
diff --git a/core/res/res/values-watch/styles_device_defaults.xml b/core/res/res/values-watch/styles_device_defaults.xml
index fb7dbb0660c5..eeb66e7cf6a8 100644
--- a/core/res/res/values-watch/styles_device_defaults.xml
+++ b/core/res/res/values-watch/styles_device_defaults.xml
@@ -42,5 +42,8 @@
<item name="indeterminateOnly">false</item>
<!-- Use Wear Material3 ring shape as default determinate drawable -->
<item name="progressDrawable">@drawable/progress_ring_watch</item>
+ <item name="indeterminateDrawable">@drawable/loader_horizontal_watch</item>
+ <item name="android:minWidth">@dimen/loader_horizontal_min_width_watch</item>
+ <item name="android:minHeight">@dimen/loader_horizontal_min_height_watch</item>
</style>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d5aa069c6e8b..c746d3c61e33 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1409,7 +1409,7 @@
<string name="carrier_app_notification_title" msgid="5815477368072060250">"已插入新 SIM 卡"</string>
<string name="carrier_app_notification_text" msgid="6567057546341958637">"点按即可进行设置"</string>
<string name="time_zone_change_notification_title" msgid="5232503069219193218">"您的时区已更改"</string>
- <string name="time_zone_change_notification_body" msgid="6135793674904665585">"您现在位于<xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
+ <string name="time_zone_change_notification_body" msgid="6135793674904665585">"您当前所处的时区是<xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string>
<string name="time_picker_dialog_title" msgid="9053376764985220821">"设置时间"</string>
<string name="date_picker_dialog_title" msgid="5030520449243071926">"设置日期"</string>
<string name="date_time_set" msgid="4603445265164486816">"设置"</string>
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"取消置顶"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"取消置顶<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"应用信息"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"直接分享目标"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"应用建议"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"应用列表"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"正在启动演示模式…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"正在重置设备…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"向左方向键"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"向右方向键"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"方向键中心"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"自动点击类型设置面板"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"点击鼠标左键"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"暂停"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"发送了一张图片"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"地图"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"应用"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"系统无法再识别您的指纹。请重新设置“指纹解锁”功能。"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"锁定时插入了 USB 设备"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"在 Android 设备锁定时插入了 USB 设备。如需使用 USB 设备,请先解锁 Android 设备,然后重新插入 USB 设备才能使用 USB 设备。"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"可疑的 USB 活动"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB 数据信号已停用。"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 91c852146be7..c6b952c99b50 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"取消固定"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"取消將<xliff:g id="LABEL">%1$s</xliff:g>置頂"</string>
<string name="app_info" msgid="6113278084877079851">"應用程式資料"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"直接分享對象"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"應用程式建議"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"應用程式清單"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"正在開始示範…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"正在重設裝置…"</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"十字鍵向左鍵"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"十字鍵向右鍵"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"十字鍵中心鍵"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"自動點擊類型設定面板"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"按一下左鍵"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"暫停"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"已傳送圖片"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"地圖"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"應用程式"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"無法再辨識你的指紋。請重新設定「指紋解鎖」功能。"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB 裝置插入時已鎖定"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB 裝置插入時,Android 已鎖定。如要使用裝置,請先解鎖 Android,然後重新插入 USB 裝置,才能使用。"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"可疑的 USB 活動"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB 資料訊號已停用。"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 1a71fedeef65..ca0402a1fe2c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"取消固定"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"將「<xliff:g id="LABEL">%1$s</xliff:g>」取消固定"</string>
<string name="app_info" msgid="6113278084877079851">"應用程式資訊"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"直接分享目標"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"應用程式建議"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"應用程式清單"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"正在啟動示範模式..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"正在重設裝置..."</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad 向左移"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad 向右移"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad 置中"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"自動點選類型設定面板"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"按滑鼠左鍵"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"暫停"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"傳送了一張圖片"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"地圖"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"應用程式"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"系統無法再辨識你的指紋,請重新設定「指紋解鎖」。"</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"在鎖定時插入 USB 裝置"</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"在 Android 裝置鎖定時插入 USB 裝置。如要使用 USB 裝置,請先解鎖 Android 裝置再重新插入。"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"可疑的 USB 活動"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB 資料信號已停用。"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 3eb20d6da55b..96d6b57ffb4e 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -2088,12 +2088,9 @@
<string name="unpin_target" msgid="3963318576590204447">"Susa ukuphina"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Susa ukuphina ku-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Ulwazi nge-app"</string>
- <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) -->
- <skip />
- <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) -->
- <skip />
- <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) -->
- <skip />
+ <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Qondisa ofuna ukwabelana nabo"</string>
+ <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Iziphakamiso ze-app"</string>
+ <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Uhlu lwama-app"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Iqalisa i-demo..."</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Isetha kabusha idivayisi..."</string>
@@ -2248,14 +2245,18 @@
<string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Ngakwesokunxele se-Dpad"</string>
<string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Ngakwesokudla se-Dpad"</string>
<string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Isikhungo se-Dpad"</string>
- <!-- no translation found for accessibility_autoclick_type_settings_panel_title (7354373370578758696) -->
+ <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Iphaneli yamasethingi ohlobo lokuchofoza ngokuzenzekelayo"</string>
+ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Chofoza kwesokunxele"</string>
+ <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) -->
<skip />
- <!-- no translation found for accessibility_autoclick_left_click (2301793352260551080) -->
+ <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) -->
<skip />
- <!-- no translation found for accessibility_autoclick_pause (3272200156172573568) -->
+ <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) -->
<skip />
- <!-- no translation found for accessibility_autoclick_position (2933660969907663545) -->
+ <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) -->
<skip />
+ <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Misa"</string>
+ <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Indawo"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string>
<string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string>
<string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"uthumele isithombe"</string>
@@ -2530,12 +2531,8 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Amamephu"</string>
<string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Ama-application"</string>
<string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Isigxivizo somunwe wakho ngeke zisakwazi ukubonwa. Setha Ukuvula Ngesigxivizo Somunwe futhi."</string>
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) -->
- <skip />
- <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) -->
- <skip />
- <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) -->
- <skip />
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Idivayisi ye-USB iyapulagwa uma i-Android ikhiyiwe."</string>
+ <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Idivayisi ye-USB iyapulagwa uma i-Android ikhiyiwe. Ukuze usebenzisa idivayisi, sicela uvule i-Android kuqala bese uphinde ufake idivayisi ye-USB ukuze uyisebenzise."</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Umsebenzi we-USB osolisayo"</string>
+ <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Isignali yedatha ye-USB ivaliwe."</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a1f85c380a95..66111785af4f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3313,7 +3313,6 @@
<!-- Provides brief supplemental information for the view, such as the purpose of
the view when that purpose is not conveyed within its textual representation.
This property is used primarily for accessibility. -->
- <!-- @FlaggedApi("android.view.accessibility.supplemental_description") -->
<attr name="supplementalDescription" format="string" localization="suggested" />
<!-- Sets the id of a view that screen readers are requested to visit after this view.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 17acf9aed278..2188469bdf03 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -60,6 +60,7 @@
<item><xliff:g id="id">@string/status_bar_oem_satellite</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_stacked_mobile</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
@@ -94,6 +95,7 @@
<string translatable="false" name="status_bar_secure">secure</string>
<string translatable="false" name="status_bar_clock">clock</string>
<string translatable="false" name="status_bar_mobile">mobile</string>
+ <string translatable="false" name="status_bar_stacked_mobile">stacked_mobile</string>
<string translatable="false" name="status_bar_vpn">vpn</string>
<string translatable="false" name="status_bar_ethernet">ethernet</string>
<string translatable="false" name="status_bar_microphone">microphone</string>
@@ -2641,6 +2643,15 @@
<!-- MMS user agent prolfile url -->
<string name="config_mms_user_agent_profile_url" translatable="false"></string>
+ <!-- The default list of possible CMF Names|Style|ColorSource. This array can be
+ overridden device-specific resources. A wildcard (fallback) must be supplied.
+ Name - Read from `ro.boot.hardware.color` sysprop. Fallback (*) required.
+ Styles - frameworks/libs/systemui/monet/src/com/android/systemui/monet/Style.java
+ Color - `home_wallpaper` (for color extraction) or a hexadecimal int (#FFcc99) -->
+ <string-array name="theming_defaults">
+ <item>*|TONAL_SPOT|home_wallpaper</item>
+ </string-array>
+
<!-- National Language Identifier codes for the following two config items.
(from 3GPP TS 23.038 V9.1.1 Table 6.2.1.2.4.1):
0 - reserved
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index e9d87e4b5f5b..9acb2427aaab 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -580,9 +580,6 @@
<dimen name="notification_text_size">14sp</dimen>
<!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
<dimen name="notification_title_text_size">14sp</dimen>
- <!-- Size of notification text titles, 2025 redesign version (see TextAppearance.StatusBar.EventContent.Title) -->
- <!-- TODO: b/378660052 - When inlining the redesign flag, this should be updated directly in TextAppearance.DeviceDefault.Notification.Title -->
- <dimen name="notification_2025_title_text_size">16sp</dimen>
<!-- Size of big notification text titles (see TextAppearance.StatusBar.EventContent.BigTitle) -->
<dimen name="notification_big_title_text_size">16sp</dimen>
<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
diff --git a/core/res/res/values/dimens_watch.xml b/core/res/res/values/dimens_watch.xml
index 2aae98715973..19845916984b 100644
--- a/core/res/res/values/dimens_watch.xml
+++ b/core/res/res/values/dimens_watch.xml
@@ -61,4 +61,8 @@
<dimen name="disabled_alpha_wear_material3">0.12</dimen>
<!-- Alpha transparency applied to elements which are considered primary (e.g. primary text) -->
<dimen name="primary_content_alpha_wear_material3">0.38</dimen>
+
+ <!-- watch's indeterminate progress bar dimens -->
+ <dimen name="loader_horizontal_min_width">68dp</dimen>
+ <dimen name="loader_horizontal_min_height">13dp</dimen>
</resources>
diff --git a/core/res/res/values/public-final.xml b/core/res/res/values/public-final.xml
index af1e5123096d..61e2a28562d2 100644
--- a/core/res/res/values/public-final.xml
+++ b/core/res/res/values/public-final.xml
@@ -3941,7 +3941,7 @@
<!-- @FlaggedApi("android.permission.flags.replace_body_sensor_permission_enabled")
@hide @SystemApi -->
<public name="backgroundPermission"/>
- <!-- @FlaggedApi(android.view.accessibility.supplemental_description) -->
+ <!-- @FlaggedApi("android.view.accessibility.supplemental_description") -->
<public name="supplementalDescription"/>
<!-- @FlaggedApi("android.security.enable_intent_matching_flags") -->
<public name="intentMatchingFlags"/>
@@ -3969,7 +3969,7 @@
<!-- @FlaggedApi("android.permission.flags.replace_body_sensor_permission_enabled")
@hide @SystemApi -->
<public type="attr" name="backgroundPermission" id="0x010106a7" />
- <!-- @FlaggedApi(android.view.accessibility.supplemental_description) -->
+ <!-- @FlaggedApi("android.view.accessibility.supplemental_description") -->
<public type="attr" name="supplementalDescription" id="0x010106a8" />
<!-- @FlaggedApi("android.security.enable_intent_matching_flags") -->
<public type="attr" name="intentMatchingFlags" id="0x010106a9" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index abbba9d1bffa..7a93ca1e9ac6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1011,6 +1011,16 @@
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
<string name="permgroupdesc_notifications">show notifications</string>
+ <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
+ <string name="permgrouplab_xr_tracking">XR tracking data</string>
+ <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
+ <string name="permgroupdesc_xr_tracking">access XR data about you and the environment around you</string>
+
+ <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
+ <string name="permgrouplab_xr_tracking_sensitive">sensitive XR tracking data</string>
+ <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
+ <string name="permgroupdesc_xr_tracking_sensitive">access sensitive tracking data, such as eye gaze</string>
+
<!-- Title for the capability of an accessibility service to retrieve window content. -->
<string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
<!-- Description for the capability of an accessibility service to retrieve window content. -->
@@ -1875,6 +1885,45 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_mediaLocation">Allows the app to read locations from your media collection.</string>
+ <string name="permlab_eye_tracking_coarse">track your approximate eye gaze</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_eye_tracking_coarse">Allows the app to track your approximate eye gaze.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_eye_tracking_fine">track where you are looking</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_eye_tracking_fine">Allows the app to access precise eye gaze data.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_face_tracking">track your face</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_face_tracking">Allows the app to access face tracking data.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_hand_tracking">track your hands</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_hand_tracking">Allows the app to access hand tracking data.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_head_tracking">track your head</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_head_tracking">Allows the app to access head tracking data.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_scene_understanding_coarse">understand your immediate environment</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_scene_understanding_coarse">Allows the app to access tracking data about the environment directly around you.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_scene_understanding_fine">understand your immediate environment at high detail</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_scene_understanding_fine">Allows the app to access tracking data about the environment directly around you with very high detail.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_xr_tracking_in_background">access XR data while not in the foreground</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_xr_tracking_in_background">Allows the app to access XR data while not in the foreground.</string>
+
<!-- Name for an app setting that lets the user authenticate for that app using biometrics (e.g. fingerprint or face). [CHAR LIMIT=30] -->
<string name="biometric_app_setting_name">Use biometrics</string>
<!-- Name for an app setting that lets the user authenticate for that app using biometrics (e.g. fingerprint or face) or their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index da6fb3b58f21..ffcfce9c420e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -575,7 +575,6 @@
<java-symbol type="dimen" name="notification_text_size" />
<java-symbol type="dimen" name="notification_title_text_size" />
<java-symbol type="dimen" name="notification_subtext_size" />
- <java-symbol type="dimen" name="notification_2025_title_text_size" />
<java-symbol type="dimen" name="notification_top_pad" />
<java-symbol type="dimen" name="notification_top_pad_narrow" />
<java-symbol type="dimen" name="notification_top_pad_large_text" />
@@ -3235,6 +3234,8 @@
<java-symbol type="id" name="header_text" />
<java-symbol type="id" name="header_text_secondary" />
<java-symbol type="id" name="expand_button" />
+ <java-symbol type="id" name="expand_button_spacer" />
+ <java-symbol type="id" name="expand_button_container" />
<java-symbol type="id" name="expand_button_pill" />
<java-symbol type="id" name="expand_button_pill_colorized_layer" />
<java-symbol type="id" name="expand_button_number" />
@@ -3318,6 +3319,7 @@
<java-symbol type="string" name="status_bar_no_calling" />
<java-symbol type="string" name="status_bar_call_strength" />
<java-symbol type="string" name="status_bar_mobile" />
+ <java-symbol type="string" name="status_bar_stacked_mobile" />
<java-symbol type="string" name="status_bar_ethernet" />
<java-symbol type="string" name="status_bar_vpn" />
<java-symbol type="string" name="status_bar_microphone" />
@@ -5901,6 +5903,9 @@
<java-symbol type="drawable" name="ic_notification_summarization" />
<java-symbol type="dimen" name="notification_collapsed_height_with_summarization" />
+ <!-- Device CMF Theming Settings -->
+ <java-symbol type="array" name="theming_defaults" />
+
<!-- Advanced Protection Service USB feature -->
<java-symbol type="string" name="usb_apm_usb_plugged_in_when_locked_notification_title" />
<java-symbol type="string" name="usb_apm_usb_plugged_in_when_locked_notification_text" />
diff --git a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
index 5765562e2383..6fe3b6ca0c6c 100644
--- a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
+++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
@@ -26,7 +26,6 @@ import static org.junit.Assert.assertThrows;
import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -112,7 +111,6 @@ public class AutomaticZenRuleTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void testLongInputsFromParcel() {
// Create a rule with long fields, set directly via reflection so that we can confirm that
// a rule with too-long fields that comes in via a parcel has its fields truncated directly.
@@ -169,7 +167,6 @@ public class AutomaticZenRuleTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void builderConstructor_nullInputs_throws() {
assertThrows(NullPointerException.class,
() -> new AutomaticZenRule.Builder(null, Uri.parse("condition")));
@@ -178,7 +175,6 @@ public class AutomaticZenRuleTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void constructor_defaultTypeUnknown() {
AutomaticZenRule rule = new AutomaticZenRule("name", new ComponentName("pkg", "cps"), null,
Uri.parse("conditionId"), null, NotificationManager.INTERRUPTION_FILTER_PRIORITY,
@@ -188,7 +184,6 @@ public class AutomaticZenRuleTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void builder_defaultsAreSensible() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("name",
Uri.parse("conditionId")).build();
@@ -200,7 +195,6 @@ public class AutomaticZenRuleTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void validate_builderWithValidType_succeeds() throws Exception {
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
.setType(AutomaticZenRule.TYPE_BEDTIME)
@@ -209,14 +203,12 @@ public class AutomaticZenRuleTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void validate_builderWithoutType_succeeds() throws Exception {
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
rule.validate(); // No exception.
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void validate_constructorWithoutType_succeeds() throws Exception {
AutomaticZenRule rule = new AutomaticZenRule("rule", new ComponentName("pkg", "cps"),
new ComponentName("pkg", "activity"), Uri.parse("condition"), null,
@@ -225,7 +217,6 @@ public class AutomaticZenRuleTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void validate_invalidType_throws() throws Exception {
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
@@ -238,7 +229,6 @@ public class AutomaticZenRuleTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void setType_invalidType_throws() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
@@ -246,7 +236,6 @@ public class AutomaticZenRuleTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void setTypeBuilder_invalidType_throws() {
AutomaticZenRule.Builder builder = new AutomaticZenRule.Builder("rule", Uri.parse("uri"));
diff --git a/core/tests/coretests/src/android/app/NotificationManagerTest.java b/core/tests/coretests/src/android/app/NotificationManagerTest.java
index d816039d0d3c..250b9ce8d89d 100644
--- a/core/tests/coretests/src/android/app/NotificationManagerTest.java
+++ b/core/tests/coretests/src/android/app/NotificationManagerTest.java
@@ -521,7 +521,7 @@ public class NotificationManagerTest {
}
@Test
- @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @EnableFlags(Flags.FLAG_MODES_UI)
public void areAutomaticZenRulesUserManaged_handheld_isTrue() {
PackageManager pm = mock(PackageManager.class);
when(pm.hasSystemFeature(any())).thenReturn(false);
@@ -531,7 +531,7 @@ public class NotificationManagerTest {
}
@Test
- @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @EnableFlags(Flags.FLAG_MODES_UI)
public void areAutomaticZenRulesUserManaged_auto_isFalse() {
PackageManager pm = mock(PackageManager.class);
when(pm.hasSystemFeature(eq(PackageManager.FEATURE_AUTOMOTIVE))).thenReturn(true);
@@ -541,7 +541,7 @@ public class NotificationManagerTest {
}
@Test
- @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @EnableFlags(Flags.FLAG_MODES_UI)
public void areAutomaticZenRulesUserManaged_tv_isFalse() {
PackageManager pm = mock(PackageManager.class);
when(pm.hasSystemFeature(eq(PackageManager.FEATURE_LEANBACK))).thenReturn(true);
@@ -551,7 +551,7 @@ public class NotificationManagerTest {
}
@Test
- @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @EnableFlags(Flags.FLAG_MODES_UI)
public void areAutomaticZenRulesUserManaged_watch_isFalse() {
PackageManager pm = mock(PackageManager.class);
when(pm.hasSystemFeature(eq(PackageManager.FEATURE_WATCH))).thenReturn(true);
diff --git a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java
index 7b41217d6200..ab2e77e57b47 100644
--- a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java
+++ b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java
@@ -23,6 +23,8 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
+
import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -32,6 +34,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.server.backup.Flags;
+import com.google.common.truth.Expect;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -42,6 +46,7 @@ import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
@Presubmit
@@ -64,6 +69,9 @@ public class BackupRestoreEventLoggerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule
+ public final Expect expect = Expect.create();
+
@Before
public void setUp() throws Exception {
mHashDigest = MessageDigest.getInstance("SHA-256");
@@ -366,6 +374,32 @@ public class BackupRestoreEventLoggerTest {
assertThat(mLogger.getLoggingResults()).isEmpty();
}
+ @Test
+ public void testDataTypeResultToString_nullArgs() {
+ assertThrows(NullPointerException.class, () -> BackupRestoreEventLogger.toString(null));
+ }
+
+ @Test
+ public void testDataTypeResultToString_typeOnly() {
+ DataTypeResult result = new DataTypeResult("The Type is Bond, James Bond!");
+
+ expect.withMessage("toString()")
+ .that(BackupRestoreEventLogger.toString(result)).isEqualTo(
+ "type=The Type is Bond, James Bond!, successCount=0, failCount=0");
+ }
+
+ @Test
+ public void testDataTypeResultToString_allFields() {
+ DataTypeResult result = DataTypeResultTest.createDataTypeResult(
+ "The Type is Bond, James Bond!", /* successCount= */ 42, /* failCount= */ 108,
+ Map.of("D'OH!", 666, "", 0), new byte[] { 4, 8, 15, 16, 23, 42 });
+
+ expect.withMessage("toString()")
+ .that(BackupRestoreEventLogger.toString(result)).isEqualTo(
+ "type=The Type is Bond, James Bond!, successCount=42, failCount=108, "
+ + "errors={=0, D'OH!=666}, metadataHash=[4, 8, 15, 16, 23, 42]");
+ }
+
private static DataTypeResult getResultForDataType(
BackupRestoreEventLogger logger, String dataType) {
Optional<DataTypeResult> result = getResultForDataTypeIfPresent(logger, dataType);
diff --git a/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java b/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java
new file mode 100644
index 000000000000..cf9e9c6e2f95
--- /dev/null
+++ b/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.backup;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.Map;
+
+public final class DataTypeResultTest {
+
+ @Rule
+ public final Expect expect = Expect.create();
+
+ @Test
+ public void testGetters_defaultConstructorFields() {
+ var result = new DataTypeResult("The Type is Bond, James Bond!");
+
+ expect.withMessage("getDataType()").that(result.getDataType())
+ .isEqualTo("The Type is Bond, James Bond!");
+ expect.withMessage("getSuccessCount()").that(result.getSuccessCount()).isEqualTo(0);
+ expect.withMessage("getFailCount()").that(result.getFailCount()).isEqualTo(0);
+ expect.withMessage("getErrorsCount()").that(result.getErrors()).isEmpty();
+ expect.withMessage("getMetadataHash()").that(result.getMetadataHash()).isNull();
+ expect.withMessage("describeContents()").that(result.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetters_allFields() {
+ DataTypeResult result = createDataTypeResult("The Type is Bond, James Bond!",
+ /* successCount= */ 42, /* failCount= */ 108, Map.of("D'OH!", 666),
+ new byte[] { 4, 8, 15, 16, 23, 42 });
+
+ expect.withMessage("getDataType()").that(result.getDataType())
+ .isEqualTo("The Type is Bond, James Bond!");
+ expect.withMessage("getSuccessCount()").that(result.getSuccessCount()).isEqualTo(42);
+ expect.withMessage("getFailCount()").that(result.getFailCount()).isEqualTo(108);
+ expect.withMessage("getErrorsCount()").that(result.getErrors()).containsExactly("D'OH!",
+ 666);
+ expect.withMessage("getMetadataHash()").that(result.getMetadataHash()).asList()
+ .containsExactly((byte) 4, (byte) 8, (byte) 15, (byte) 16, (byte) 23, (byte) 42)
+ .inOrder();
+ expect.withMessage("describeContents()").that(result.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void testParcelMethods() {
+ DataTypeResult original = createDataTypeResult("The Type is Bond, James Bond!",
+ /* successCount= */ 42, /* failCount= */ 108, Map.of("D'OH!", 666),
+ new byte[] { 4, 8, 15, 16, 23, 42 });
+ Parcel parcel = Parcel.obtain();
+ try {
+ original.writeToParcel(parcel, /* flags= */ 0);
+
+ parcel.setDataPosition(0);
+ var clone = DataTypeResult.CREATOR.createFromParcel(parcel);
+ assertWithMessage("createFromParcel()").that(clone).isNotNull();
+
+ expect.withMessage("getDataType()").that(clone.getDataType())
+ .isEqualTo(original.getDataType());
+ expect.withMessage("getSuccessCount()").that(clone.getSuccessCount())
+ .isEqualTo(original.getSuccessCount());
+ expect.withMessage("getFailCount()").that(clone.getFailCount())
+ .isEqualTo(original.getFailCount());
+ expect.withMessage("getErrorsCount()").that(clone.getErrors())
+ .containsExactlyEntriesIn(original.getErrors()).inOrder();
+ expect.withMessage("getMetadataHash()").that(clone.getMetadataHash())
+ .isEqualTo(original.getMetadataHash());
+ expect.withMessage("describeContents()").that(clone.describeContents()).isEqualTo(0);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ static DataTypeResult createDataTypeResult(String dataType, int successCount, int failCount,
+ Map<String, Integer> errors, byte... metadataHash) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.writeString(dataType);
+ parcel.writeInt(successCount);
+ parcel.writeInt(failCount);
+ Bundle errorsBundle = new Bundle();
+ errors.entrySet()
+ .forEach(entry -> errorsBundle.putInt(entry.getKey(), entry.getValue()));
+ parcel.writeBundle(errorsBundle);
+ parcel.writeByteArray(metadataHash);
+
+ parcel.setDataPosition(0);
+ var result = DataTypeResult.CREATOR.createFromParcel(parcel);
+ assertWithMessage("createFromParcel()").that(result).isNotNull();
+ return result;
+ } finally {
+ parcel.recycle();
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
index dc2f0a69375d..9383807ec761 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
+++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
@@ -33,6 +33,7 @@ import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -348,6 +349,26 @@ public class DisplayManagerGlobalTest {
DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_COMMITTED_STATE_SEPARATE_EVENT)
+ public void test_mapPrivateEventCommittedStateChanged_flagEnabled() {
+ // Test public flags mapping
+ assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_COMMITTED_STATE_CHANGED,
+ mDisplayManagerGlobal
+ .mapFiltersToInternalEventFlag(0,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_COMMITTED_STATE_CHANGED));
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_COMMITTED_STATE_SEPARATE_EVENT)
+ public void test_mapPrivateEventCommittedStateChanged_flagDisabled() {
+ // Test public flags mapping
+ assertEquals(0,
+ mDisplayManagerGlobal
+ .mapFiltersToInternalEventFlag(0,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_COMMITTED_STATE_CHANGED));
+ }
+
private void waitForHandler() {
mHandler.runWithScissors(() -> {
}, 0);
diff --git a/core/tests/coretests/src/android/service/notification/ConditionTest.java b/core/tests/coretests/src/android/service/notification/ConditionTest.java
index e94273e1ada7..65c108a827ef 100644
--- a/core/tests/coretests/src/android/service/notification/ConditionTest.java
+++ b/core/tests/coretests/src/android/service/notification/ConditionTest.java
@@ -23,10 +23,8 @@ import static junit.framework.Assert.fail;
import static org.junit.Assert.assertThrows;
-import android.app.Flags;
import android.net.Uri;
import android.os.Parcel;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -113,7 +111,6 @@ public class ConditionTest {
@Test
public void testLongFields_inConstructors() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
String longString = Strings.repeat("A", 65536);
Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
@@ -136,7 +133,6 @@ public class ConditionTest {
@Test
public void testLongFields_viaParcel() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
// Set fields via reflection to force them to be long, then parcel and unparcel to make sure
// it gets truncated upon unparcelling.
Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder",
@@ -170,8 +166,6 @@ public class ConditionTest {
@Test
public void testEquals() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
Condition cond1 = new Condition(Uri.parse("uri://placeholder"), "placeholder",
Condition.STATE_TRUE, Condition.SOURCE_USER_ACTION);
Condition cond2 = new Condition(Uri.parse("uri://placeholder"), "placeholder",
@@ -186,8 +180,6 @@ public class ConditionTest {
@Test
public void testParcelConstructor() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder",
Condition.STATE_TRUE, Condition.SOURCE_USER_ACTION);
@@ -200,28 +192,24 @@ public class ConditionTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void constructor_unspecifiedSource_succeeds() {
new Condition(Uri.parse("id"), "Summary", Condition.STATE_TRUE);
// No exception.
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void constructor_validSource_succeeds() {
new Condition(Uri.parse("id"), "Summary", Condition.STATE_TRUE, Condition.SOURCE_CONTEXT);
// No exception.
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void constructor_invalidSource_throws() {
assertThrows(IllegalArgumentException.class,
() -> new Condition(Uri.parse("uri"), "Summary", Condition.STATE_TRUE, 1000));
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void constructor_parcelWithInvalidSource_throws() {
Condition original = new Condition(Uri.parse("condition"), "Summary", Condition.STATE_TRUE,
Condition.SOURCE_SCHEDULE);
@@ -237,7 +225,6 @@ public class ConditionTest {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void validate_invalidSource_throws() throws Exception {
Condition condition = new Condition(Uri.parse("condition"), "Summary", Condition.STATE_TRUE,
Condition.SOURCE_SCHEDULE);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 9f398ecf5492..b7d6ab56d6b3 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -79,6 +79,7 @@ import android.graphics.drawable.Icon;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.DeviceConfig;
import android.service.chooser.ChooserTarget;
import android.util.Pair;
@@ -3178,7 +3179,11 @@ public class ChooserActivityTest {
}
private void markWorkProfileUserAvailable() {
- ChooserActivityOverrideData.getInstance().workProfileUserHandle = UserHandle.of(10);
+ if (UserManager.isHeadlessSystemUserMode()) {
+ ChooserActivityOverrideData.getInstance().workProfileUserHandle = UserHandle.of(11);
+ } else {
+ ChooserActivityOverrideData.getInstance().workProfileUserHandle = UserHandle.of(10);
+ }
}
private void markCloneProfileUserAvailable() {
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index dcea9120e2a5..be7f84e3ea8f 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -155,12 +155,12 @@ public class ChooserWrapperActivity extends ChooserActivity implements IChooserW
@Override
protected ResolverListController createListController(UserHandle userHandle) {
- if (userHandle == UserHandle.SYSTEM) {
- when(sOverrides.resolverListController.getUserHandle()).thenReturn(UserHandle.SYSTEM);
- return sOverrides.resolverListController;
+ if (userHandle.equals(sOverrides.workProfileUserHandle)) {
+ when(sOverrides.workResolverListController.getUserHandle()).thenReturn(userHandle);
+ return sOverrides.workResolverListController;
}
- when(sOverrides.workResolverListController.getUserHandle()).thenReturn(userHandle);
- return sOverrides.workResolverListController;
+ when(sOverrides.resolverListController.getUserHandle()).thenReturn(userHandle);
+ return sOverrides.resolverListController;
}
@Override
diff --git a/core/tests/coretests/src/com/android/internal/util/RateLimitingCacheTest.java b/core/tests/coretests/src/com/android/internal/util/RateLimitingCacheTest.java
index 2edab6268bec..82d90fc71cb3 100644
--- a/core/tests/coretests/src/com/android/internal/util/RateLimitingCacheTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/RateLimitingCacheTest.java
@@ -21,8 +21,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.os.SystemClock;
-
-import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
@@ -36,6 +35,7 @@ import org.junit.runner.RunWith;
/**
* Test the RateLimitingCache class.
*/
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class RateLimitingCacheTest {
@@ -56,13 +56,13 @@ public class RateLimitingCacheTest {
*/
@Test
public void testTtl_Zero() {
- RateLimitingCache<Integer> s = new RateLimitingCache<>(0);
+ TestRateLimitingCache<Integer> s = new TestRateLimitingCache<>(0);
int first = s.get(mFetcher);
assertEquals(first, 0);
int second = s.get(mFetcher);
assertEquals(second, 1);
- SystemClock.sleep(20);
+ s.advanceTime(20);
int third = s.get(mFetcher);
assertEquals(third, 2);
}
@@ -73,14 +73,14 @@ public class RateLimitingCacheTest {
*/
@Test
public void testTtl_100() {
- RateLimitingCache<Integer> s = new RateLimitingCache<>(100);
+ TestRateLimitingCache<Integer> s = new TestRateLimitingCache<>(100);
int first = s.get(mFetcher);
assertEquals(first, 0);
int second = s.get(mFetcher);
// Too early to change
assertEquals(second, 0);
- SystemClock.sleep(150);
+ s.advanceTime(150);
int third = s.get(mFetcher);
// Changed by now
assertEquals(third, 1);
@@ -95,11 +95,11 @@ public class RateLimitingCacheTest {
*/
@Test
public void testTtl_Negative() {
- RateLimitingCache<Integer> s = new RateLimitingCache<>(-1);
+ TestRateLimitingCache<Integer> s = new TestRateLimitingCache<>(-1);
int first = s.get(mFetcher);
assertEquals(first, 0);
- SystemClock.sleep(200);
+ s.advanceTime(200);
// Should return the original value every time
int second = s.get(mFetcher);
assertEquals(second, 0);
@@ -111,7 +111,7 @@ public class RateLimitingCacheTest {
*/
@Test
public void testTtl_Spam() {
- RateLimitingCache<Integer> s = new RateLimitingCache<>(100);
+ TestRateLimitingCache<Integer> s = new TestRateLimitingCache<>(100);
assertCount(s, 1000, 7, 15);
}
@@ -121,28 +121,13 @@ public class RateLimitingCacheTest {
*/
@Test
public void testRate_10hz() {
- RateLimitingCache<Integer> s = new RateLimitingCache<>(1000, 10);
+ TestRateLimitingCache<Integer> s = new TestRateLimitingCache<>(1000, 10);
// At 10 per second, 2 seconds should not exceed about 30, assuming overlap into left and
// right windows that allow 10 each
assertCount(s, 2000, 20, 33);
}
/**
- * Test that using a different timebase works correctly.
- */
- @Test
- public void testTimebase() {
- RateLimitingCache<Integer> s = new RateLimitingCache<>(1000, 10) {
- @Override
- protected long getTime() {
- return SystemClock.elapsedRealtime() / 2;
- }
- };
- // Timebase is moving at half the speed, so only allows for 1 second worth in 2 seconds.
- assertCount(s, 2000, 10, 22);
- }
-
- /**
* Exercises concurrent access to the cache.
*/
@Test
@@ -287,15 +272,37 @@ public class RateLimitingCacheTest {
* @param minCount the lower end of the expected number of fetches, with a margin for error
* @param maxCount the higher end of the expected number of fetches, with a margin for error
*/
- private void assertCount(RateLimitingCache<Integer> cache, long period,
+ private void assertCount(TestRateLimitingCache<Integer> cache, long period,
int minCount, int maxCount) {
- long startTime = SystemClock.elapsedRealtime();
- while (SystemClock.elapsedRealtime() < startTime + period) {
+ long startTime = cache.getTime();
+ while (cache.getTime() < startTime + period) {
int value = cache.get(mFetcher);
- SystemClock.sleep(5);
+ cache.advanceTime(5);
}
int latest = cache.get(mFetcher);
assertTrue("Latest should be between " + minCount + " and " + maxCount
+ " but is " + latest, latest <= maxCount && latest >= minCount);
}
+
+ private static class TestRateLimitingCache<Value> extends RateLimitingCache<Value> {
+ // Start at a non-zero time to avoid confusion with uninitialized state.
+ private long mTime = 1;
+
+ public TestRateLimitingCache(long periodMillis) {
+ super(periodMillis);
+ }
+
+ public TestRateLimitingCache(long periodMillis, int count) {
+ super(periodMillis, count);
+ }
+
+ public void advanceTime(long time) {
+ mTime += time;
+ }
+
+ @Override
+ public long getTime() {
+ return mTime;
+ }
+ }
}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index baaec86828eb..ca20aebf95d8 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -210,6 +210,7 @@
<assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="statsd" />
+ <assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="mmd" />
<assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="gpu_service" />
<assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="keystore" />
diff --git a/data/fonts/script/test/test_commandline.py b/data/fonts/script/test/test_commandline.py
index 75318cc10e68..dbcba417c5e1 100755
--- a/data/fonts/script/test/test_commandline.py
+++ b/data/fonts/script/test/test_commandline.py
@@ -75,20 +75,20 @@ class CommandlineTest(unittest.TestCase):
functools.partial(CommandlineTest.fileread, filemap),
)
- self.assertEquals("output.xml", args.outfile)
+ self.assertEqual("output.xml", args.outfile)
- self.assertEquals(1, len(args.aliases))
- self.assertEquals("sans-serif-thin", args.aliases[0].name)
- self.assertEquals("sans-serif", args.aliases[0].to)
- self.assertEquals(100, args.aliases[0].weight)
+ self.assertEqual(1, len(args.aliases))
+ self.assertEqual("sans-serif-thin", args.aliases[0].name)
+ self.assertEqual("sans-serif", args.aliases[0].to)
+ self.assertEqual(100, args.aliases[0].weight)
- self.assertEquals(2, len(args.fallback))
+ self.assertEqual(2, len(args.fallback))
# Order is not a part of expectation. Check the expected lang is included.
langs = set(["und-Arab", "und-Ethi"])
self.assertTrue(args.fallback[0].lang in langs)
self.assertTrue(args.fallback[1].lang in langs)
- self.assertEquals(3, len(args.families))
+ self.assertEqual(3, len(args.families))
# Order is not a part of expectation. Check the expected name is included.
names = set(["sans-serif", "sans-serif-condensed", "roboto-flex"])
self.assertTrue(args.families[0].name in names)
diff --git a/data/fonts/script/test/test_xml_builder.py b/data/fonts/script/test/test_xml_builder.py
index 24a033b43cbc..f15c51379b46 100755
--- a/data/fonts/script/test/test_xml_builder.py
+++ b/data/fonts/script/test/test_xml_builder.py
@@ -328,16 +328,16 @@ class XmlBuilderTest(unittest.TestCase):
self.expect_xml(xml)
def expect_xml(self, xml):
- self.assertEquals("sans-serif", xml.families[0].name) # _SANS_SERIF
- self.assertEquals("serif", xml.families[1].name) # _SERIF
- self.assertEquals("und-Arab", xml.families[2].lang) # __ARABIC
- self.assertEquals("elegant", xml.families[2].variant)
- self.assertEquals("und-Arab", xml.families[3].lang) # _ARABIC_UI
- self.assertEquals("zh-Hans", xml.families[4].lang) # _HANS (_HANS_SERIF)
- self.assertEquals(2, len(xml.families[4].fonts))
- self.assertEquals("serif", xml.families[4].fonts[1].fallback_for)
- self.assertEquals("ja", xml.families[5].lang) # _HANS (_HANS_SERIF)
- self.assertEquals("serif", xml.families[5].fonts[1].fallback_for)
+ self.assertEqual("sans-serif", xml.families[0].name) # _SANS_SERIF
+ self.assertEqual("serif", xml.families[1].name) # _SERIF
+ self.assertEqual("und-Arab", xml.families[2].lang) # __ARABIC
+ self.assertEqual("elegant", xml.families[2].variant)
+ self.assertEqual("und-Arab", xml.families[3].lang) # _ARABIC_UI
+ self.assertEqual("zh-Hans", xml.families[4].lang) # _HANS (_HANS_SERIF)
+ self.assertEqual(2, len(xml.families[4].fonts))
+ self.assertEqual("serif", xml.families[4].fonts[1].fallback_for)
+ self.assertEqual("ja", xml.families[5].lang) # _HANS (_HANS_SERIF)
+ self.assertEqual("serif", xml.families[5].fonts[1].fallback_for)
if __name__ == "__main__":
diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java
index 7d236d203201..3b8f46630344 100644
--- a/graphics/java/android/graphics/FrameInfo.java
+++ b/graphics/java/android/graphics/FrameInfo.java
@@ -93,10 +93,12 @@ public final class FrameInfo {
// Interval between two consecutive frames
public static final int FRAME_INTERVAL = 11;
+ // Workload target deadline for a frame
+ public static final int WORKLOAD_TARGET = 12;
+
// Must be the last one
// This value must be in sync with `UI_THREAD_FRAME_INFO_SIZE` in FrameInfo.h
- // In calculating size, + 1 for Flags, and + 1 for WorkloadTarget from FrameInfo.h
- private static final int FRAME_INFO_SIZE = FRAME_INTERVAL + 2;
+ private static final int FRAME_INFO_SIZE = WORKLOAD_TARGET + 1;
/** checkstyle */
public void setVsync(long intendedVsync, long usedVsync, long frameTimelineVsyncId,
@@ -108,6 +110,7 @@ public final class FrameInfo {
frameInfo[FRAME_DEADLINE] = frameDeadline;
frameInfo[FRAME_START_TIME] = frameStartTime;
frameInfo[FRAME_INTERVAL] = frameInterval;
+ frameInfo[WORKLOAD_TARGET] = frameDeadline - intendedVsync;
}
/** checkstyle */
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 940cd93c53f2..65854dd51a91 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -1467,6 +1467,18 @@ public class HardwareRenderer {
public static native void preload();
/**
+ * Initialize the Buffer Allocator singleton
+ *
+ * This takes 10-20ms on low-resourced devices, so doing it on-demand when an app
+ * tries to render its first frame causes drawFrames to be blocked for buffer
+ * allocation due to just initializing the allocator.
+ *
+ * Should only be called when a buffer is expected to be used.
+ * @hide
+ */
+ public static native void preInitBufferAllocator();
+
+ /**
* @hide
*/
protected static native boolean isWebViewOverlaysEnabled();
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 3543e991924e..db2376e008f5 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -20,6 +20,7 @@ import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.ArrayMap;
import android.view.Window;
@@ -76,6 +77,7 @@ import libcore.util.NativeAllocationRegistry;
* Additionally, if the shader is invoked by another using {@link #setInputShader(String, Shader)},
* then that parent shader may modify the input coordinates arbitrarily.</p>
*
+ * <a id="agsl-and-color-spaces"/>
* <h3>AGSL and Color Spaces</h3>
* <p>Android Graphics and by extension {@link RuntimeShader} are color managed. The working
* {@link ColorSpace} for an AGSL shader is defined to be the color space of the destination, which
@@ -267,6 +269,8 @@ public class RuntimeShader extends Shader {
private ArrayMap<String, ColorFilter> mColorFilterUniforms = new ArrayMap<>();
private ArrayMap<String, RuntimeXfermode> mXfermodeUniforms = new ArrayMap<>();
+ private ColorSpace mWorkingColorSpace = null;
+
/**
* Creates a new RuntimeShader.
@@ -286,6 +290,35 @@ public class RuntimeShader extends Shader {
}
/**
+ * Sets the working color space for this shader. That is, the shader will be evaluated
+ * in the given colorspace before being converted to the output destination's colorspace.
+ *
+ * <p>By default the RuntimeShader is evaluated in the context of the
+ * <a href="#agsl-and-color-spaces">destination colorspace</a>. By calling this method
+ * that can be overridden to force the shader to be evaluated in the given colorspace first
+ * before then being color converted to the destination colorspace.</p>
+ *
+ * @param colorSpace The ColorSpace to evaluate in. Must be an {@link ColorSpace#getModel() RGB}
+ * ColorSpace. Passing null restores default behavior of working in the
+ * destination colorspace.
+ * @throws IllegalArgumentException If the colorspace is not RGB
+ */
+ @FlaggedApi(Flags.FLAG_SHADER_COLOR_SPACE)
+ public void setWorkingColorSpace(@Nullable ColorSpace colorSpace) {
+ if (colorSpace != null && colorSpace.getModel() != ColorSpace.Model.RGB) {
+ throw new IllegalArgumentException("ColorSpace must be RGB, given " + colorSpace);
+ }
+ if (mWorkingColorSpace != colorSpace) {
+ mWorkingColorSpace = colorSpace;
+ if (mWorkingColorSpace != null) {
+ // Just to enforce this can be resolved instead of erroring out later
+ mWorkingColorSpace.getNativeInstance();
+ }
+ discardNativeInstance();
+ }
+ }
+
+ /**
* Sets the uniform color value corresponding to this shader. If the shader does not have a
* uniform with that name or if the uniform is declared with a type other than vec3 or vec4 and
* corresponding layout(color) annotation then an IllegalArgumentException is thrown.
@@ -578,7 +611,8 @@ public class RuntimeShader extends Shader {
/** @hide */
@Override
protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
- return nativeCreateShader(mNativeInstanceRuntimeShaderBuilder, nativeMatrix);
+ return nativeCreateShader(mNativeInstanceRuntimeShaderBuilder, nativeMatrix,
+ mWorkingColorSpace != null ? mWorkingColorSpace.getNativeInstance() : 0);
}
/** @hide */
@@ -589,6 +623,8 @@ public class RuntimeShader extends Shader {
private static native long nativeGetFinalizer();
private static native long nativeCreateBuilder(String agsl);
private static native long nativeCreateShader(long shaderBuilder, long matrix);
+ private static native long nativeCreateShader(long shaderBuilder, long matrix,
+ long colorSpacePtr);
private static native void nativeUpdateUniforms(
long shaderBuilder, String uniformName, float[] uniforms, boolean isColor);
private static native void nativeUpdateUniforms(
diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java
index 464714fe2895..c2792e1f2394 100644
--- a/keystore/java/android/security/GateKeeper.java
+++ b/keystore/java/android/security/GateKeeper.java
@@ -28,7 +28,7 @@ import android.service.gatekeeper.IGateKeeperService;
*
* @hide
*/
-public abstract class GateKeeper {
+public final class GateKeeper {
public static final long INVALID_SECURE_USER_ID = 0;
diff --git a/keystore/java/android/security/keystore/ArrayUtils.java b/keystore/java/android/security/keystore/ArrayUtils.java
index f22b6041800f..6472ca9957d0 100644
--- a/keystore/java/android/security/keystore/ArrayUtils.java
+++ b/keystore/java/android/security/keystore/ArrayUtils.java
@@ -23,7 +23,7 @@ import java.util.function.Consumer;
/**
* @hide
*/
-public abstract class ArrayUtils {
+public final class ArrayUtils {
private ArrayUtils() {}
public static String[] nullToEmpty(String[] array) {
diff --git a/keystore/java/android/security/keystore/Utils.java b/keystore/java/android/security/keystore/Utils.java
index e58b1ccb5370..c38ce8e86a15 100644
--- a/keystore/java/android/security/keystore/Utils.java
+++ b/keystore/java/android/security/keystore/Utils.java
@@ -23,7 +23,7 @@ import java.util.Date;
*
* @hide
*/
-abstract class Utils {
+public final class Utils {
private Utils() {}
static Date cloneIfNotNull(Date value) {
diff --git a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
index 1394bd443f03..9d306ce1ed38 100644
--- a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
@@ -38,7 +38,9 @@ import java.util.function.Consumer;
/**
* @hide
*/
-public abstract class KeyStore2ParameterUtils {
+public final class KeyStore2ParameterUtils {
+
+ private KeyStore2ParameterUtils() {}
/**
* This function constructs a {@link KeyParameter} expressing a boolean value.
diff --git a/keystore/java/android/security/keystore2/KeymasterUtils.java b/keystore/java/android/security/keystore2/KeymasterUtils.java
index 614e3684c417..02f3f578d03e 100644
--- a/keystore/java/android/security/keystore2/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore2/KeymasterUtils.java
@@ -16,13 +16,10 @@
package android.security.keystore2;
-import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
-import android.security.keystore.KeyProperties;
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.InvalidParameterSpecException;
@@ -30,7 +27,7 @@ import java.security.spec.InvalidParameterSpecException;
/**
* @hide
*/
-public abstract class KeymasterUtils {
+public final class KeymasterUtils {
private KeymasterUtils() {}
@@ -86,47 +83,6 @@ public abstract class KeymasterUtils {
}
}
- /**
- * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
- * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
- * AES-GCM).
- */
- public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
- int keymasterAlgorithm,
- int[] keymasterBlockModes,
- int[] keymasterDigests) {
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_AES:
- if (com.android.internal.util.ArrayUtils.contains(
- keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
- // AES GCM key needs the minimum length of AEAD tag specified.
- args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
- AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
- .MIN_SUPPORTED_TAG_LENGTH_BITS);
- }
- break;
- case KeymasterDefs.KM_ALGORITHM_HMAC:
- // HMAC key needs the minimum length of MAC set to the output size of the associated
- // digest. This is because we do not offer a way to generate shorter MACs and
- // don't offer a way to verify MACs (other than by generating them).
- if (keymasterDigests.length != 1) {
- throw new ProviderException(
- "Unsupported number of authorized digests for HMAC key: "
- + keymasterDigests.length
- + ". Exactly one digest must be authorized");
- }
- int keymasterDigest = keymasterDigests[0];
- int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
- if (digestOutputSizeBits == -1) {
- throw new ProviderException(
- "HMAC key authorized for unsupported digest: "
- + KeyProperties.Digest.fromKeymaster(keymasterDigest));
- }
- args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
- break;
- }
- }
-
static String getEcCurveFromKeymaster(int ecCurve) {
switch (ecCurve) {
case android.hardware.security.keymint.EcCurve.P_224:
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index ab2f3ef94eb6..68970e68de07 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -3,5 +3,5 @@ pbdr@google.com
pragyabajoria@google.com
# Give submodule owners in shell resource approval
-per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, lbill@google.com, madym@google.com, vaniadesmonda@google.com, pbdr@google.com, mpodolian@google.com, liranb@google.com, pragyabajoria@google.com, uysalorhan@google.com, gsennton@google.com, mattsziklay@google.com, mdehaini@google.com
+per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, lbill@google.com, madym@google.com, vaniadesmonda@google.com, pbdr@google.com, mpodolian@google.com, liranb@google.com, pragyabajoria@google.com, uysalorhan@google.com, gsennton@google.com, mattsziklay@google.com, mdehaini@google.com, peanutbutter@google.com, jeremysim@google.com
per-file res*/*/tv_*.xml = bronger@google.com
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.png
new file mode 100644
index 000000000000..15198748eea5
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.png
new file mode 100644
index 000000000000..99673f6400e9
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.png
new file mode 100644
index 000000000000..ba4ebab75a7e
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.png
new file mode 100644
index 000000000000..b3ff64401a96
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.png
new file mode 100644
index 000000000000..534e320a0596
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.png
new file mode 100644
index 000000000000..67c9f49171ba
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.png
new file mode 100644
index 000000000000..a0fb4902a6f3
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.png
new file mode 100644
index 000000000000..27b35d447868
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.png
new file mode 100644
index 000000000000..11528a028a8f
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.png
new file mode 100644
index 000000000000..ef9937700c08
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.png
new file mode 100644
index 000000000000..f0cf08bfcf4e
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.png
new file mode 100644
index 000000000000..bbaafb39845a
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.png
new file mode 100644
index 000000000000..38ebf3f3201a
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.png
new file mode 100644
index 000000000000..2e4fd51e3932
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.png
new file mode 100644
index 000000000000..a1ba9fb50d6a
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.png
new file mode 100644
index 000000000000..51bb15e10d30
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.png
new file mode 100644
index 000000000000..b643e2a69b2c
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.png
new file mode 100644
index 000000000000..e6eeab7129be
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt b/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt
new file mode 100644
index 000000000000..24f43d347163
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.shared.bubbles
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.view.View
+import android.view.WindowManager
+import android.widget.FrameLayout
+import androidx.annotation.ColorInt
+import androidx.core.graphics.blue
+import androidx.core.graphics.green
+import androidx.core.graphics.red
+import androidx.core.graphics.toColorInt
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import com.android.wm.shell.shared.bubbles.DragZoneFactory.DesktopWindowModeChecker
+import com.android.wm.shell.shared.bubbles.DragZoneFactory.SplitScreenModeChecker
+import com.android.wm.shell.shared.bubbles.DragZoneFactory.SplitScreenModeChecker.SplitScreenMode
+import com.android.wm.shell.testing.goldenpathmanager.WMShellGoldenPathManager
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.Displays
+import platform.test.screenshot.ViewScreenshotTestRule
+import platform.test.screenshot.ViewScreenshotTestRule.Mode
+import platform.test.screenshot.getEmulatedDevicePathConfig
+
+@RunWith(ParameterizedAndroidJunit4::class)
+class DragZoneFactoryScreenshotTest(private val param: Param) {
+ companion object {
+ @Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs(): List<Param> {
+ val params = mutableListOf<Param>()
+ val draggedObjects =
+ listOf(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ DraggedObject.BubbleBar(BubbleBarLocation.LEFT),
+ DraggedObject.ExpandedView(BubbleBarLocation.LEFT),
+ )
+ DeviceEmulationSpec.forDisplays(Displays.Tablet, isDarkTheme = false).forEach { tablet
+ ->
+ draggedObjects.forEach { draggedObject ->
+ params.add(Param(tablet, draggedObject, SplitScreenMode.NONE))
+ }
+ }
+ DeviceEmulationSpec.forDisplays(Displays.FoldableInner, isDarkTheme = false).forEach {
+ foldable ->
+ draggedObjects.forEach { draggedObject ->
+ params.add(Param(foldable, draggedObject, SplitScreenMode.NONE))
+ val isBubble = draggedObject is DraggedObject.Bubble
+ val isExpandedView = draggedObject is DraggedObject.ExpandedView
+ val addMoreSplitModes = isBubble || (isExpandedView && foldable.isLandscape)
+ if (addMoreSplitModes) {
+ params.add(Param(foldable, draggedObject, SplitScreenMode.SPLIT_10_90))
+ params.add(Param(foldable, draggedObject, SplitScreenMode.SPLIT_90_10))
+ }
+ }
+ }
+ return params
+ }
+ }
+
+ class Param(
+ val emulationSpec: DeviceEmulationSpec,
+ val draggedObject: DraggedObject,
+ val splitScreenMode: SplitScreenMode
+ ) {
+ private val draggedObjectName =
+ when (draggedObject) {
+ is DraggedObject.Bubble -> "bubble"
+ is DraggedObject.BubbleBar -> "bubbleBar"
+ is DraggedObject.ExpandedView -> "expandedView"
+ }
+
+ private val splitScreenModeName =
+ when (splitScreenMode) {
+ SplitScreenMode.NONE -> ""
+ SplitScreenMode.SPLIT_50_50 -> "_split_50_50"
+ SplitScreenMode.SPLIT_10_90 -> "_split_10_90"
+ SplitScreenMode.SPLIT_90_10 -> "_split_90_10"
+ }
+
+ val testName = "$draggedObjectName$splitScreenModeName"
+
+ override fun toString() = "${emulationSpec}_$testName"
+ }
+
+ @get:Rule
+ val screenshotRule =
+ ViewScreenshotTestRule(
+ param.emulationSpec,
+ WMShellGoldenPathManager(getEmulatedDevicePathConfig(param.emulationSpec))
+ )
+
+ private val context = getApplicationContext<Context>()
+
+ @Test
+ fun dragZones() {
+ screenshotRule.screenshotTest("dragZones_${param.testName}", mode = Mode.MatchSize) {
+ activity ->
+ activity.actionBar?.hide()
+ val dragZoneFactory = createDragZoneFactory()
+ val dragZones = dragZoneFactory.createSortedDragZones(param.draggedObject)
+ val container = FrameLayout(context)
+ dragZones.forEach { zone -> container.addZoneView(zone) }
+ container
+ }
+ }
+
+ private fun createDragZoneFactory(): DragZoneFactory {
+ val deviceConfig =
+ DeviceConfig.create(context, context.getSystemService(WindowManager::class.java)!!)
+ val splitScreenModeChecker = SplitScreenModeChecker { param.splitScreenMode }
+ val desktopWindowModeChecker = DesktopWindowModeChecker { true }
+ return DragZoneFactory(
+ context,
+ deviceConfig,
+ splitScreenModeChecker,
+ desktopWindowModeChecker
+ )
+ }
+
+ private fun FrameLayout.addZoneView(zone: DragZone) {
+ val view = View(context)
+ this.addView(view, 0)
+ view.layoutParams = FrameLayout.LayoutParams(zone.bounds.width(), zone.bounds.height())
+ view.background = createZoneDrawable(zone.color)
+ view.x = zone.bounds.left.toFloat()
+ view.y = zone.bounds.top.toFloat()
+ }
+
+ private fun createZoneDrawable(@ColorInt color: Int): Drawable {
+ val shape = GradientDrawable()
+ shape.shape = GradientDrawable.RECTANGLE
+ shape.setColor(Color.argb(128, color.red, color.green, color.blue))
+ shape.setStroke(2, color)
+ return shape
+ }
+
+ private val DragZone.color: Int
+ @ColorInt
+ get() =
+ when (this) {
+ is DragZone.Bubble -> "#3F5C8B".toColorInt()
+ is DragZone.Dismiss -> "#8B3F3F".toColorInt()
+ is DragZone.Split -> "#89B675".toColorInt()
+ is DragZone.FullScreen -> "#4ED075".toColorInt()
+ is DragZone.DesktopWindow -> "#EC928E".toColorInt()
+ }
+}
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt
new file mode 100644
index 000000000000..9ebc3d78b3a7
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.bubbles
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ShortcutInfo
+import android.graphics.drawable.Icon
+import android.os.UserHandle
+import android.service.notification.NotificationListenerService.Ranking
+import android.service.notification.StatusBarNotification
+import android.view.View
+import android.widget.FrameLayout
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.R
+import com.android.wm.shell.bubbles.Bubbles.BubbleMetadataFlagListener
+import com.android.wm.shell.common.TestShellExecutor
+import com.android.wm.shell.taskview.TaskView
+import com.android.wm.shell.taskview.TaskViewController
+import com.android.wm.shell.taskview.TaskViewTaskController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/**
+ * Tests for [BubbleTaskViewListener].
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BubbleTaskViewListenerTest {
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+
+ private var taskViewController = mock<TaskViewController>()
+ private var listenerCallback = mock<BubbleTaskViewListener.Callback>()
+ private var expandedViewManager = mock<BubbleExpandedViewManager>()
+
+ private lateinit var bubbleTaskViewListener: BubbleTaskViewListener
+ private lateinit var taskView: TaskView
+ private lateinit var bubbleTaskView: BubbleTaskView
+ private lateinit var parentView: ViewPoster
+ private lateinit var mainExecutor: TestShellExecutor
+ private lateinit var bgExecutor: TestShellExecutor
+
+ @Before
+ fun setUp() {
+ ProtoLog.REQUIRE_PROTOLOGTOOL = false
+ ProtoLog.init()
+
+ parentView = ViewPoster(context)
+ mainExecutor = TestShellExecutor()
+ bgExecutor = TestShellExecutor()
+
+ taskView = TaskView(context, taskViewController, mock<TaskViewTaskController>())
+ bubbleTaskView = BubbleTaskView(taskView, mainExecutor)
+
+ bubbleTaskViewListener =
+ BubbleTaskViewListener(
+ context,
+ bubbleTaskView,
+ parentView,
+ expandedViewManager,
+ listenerCallback
+ )
+ }
+
+ @Test
+ fun createBubbleTaskViewListener_withCreatedTaskView() {
+ // Make the bubbleTaskView look like it's been created
+ val taskId = 123
+ bubbleTaskView.listener.onTaskCreated(taskId, mock<ComponentName>())
+ reset(listenerCallback)
+
+ bubbleTaskViewListener =
+ BubbleTaskViewListener(
+ context,
+ bubbleTaskView,
+ parentView,
+ expandedViewManager,
+ listenerCallback
+ )
+
+ assertThat(bubbleTaskView.delegateListener).isEqualTo(bubbleTaskViewListener)
+ assertThat(bubbleTaskViewListener.taskView).isEqualTo(bubbleTaskView.taskView)
+
+ verify(listenerCallback).onTaskCreated()
+ assertThat(bubbleTaskViewListener.taskId).isEqualTo(taskId)
+ }
+
+ @Test
+ fun createBubbleTaskViewListener() {
+ bubbleTaskViewListener =
+ BubbleTaskViewListener(
+ context,
+ bubbleTaskView,
+ parentView,
+ expandedViewManager,
+ listenerCallback
+ )
+
+ assertThat(bubbleTaskView.delegateListener).isEqualTo(bubbleTaskViewListener)
+ assertThat(bubbleTaskViewListener.taskView).isEqualTo(bubbleTaskView.taskView)
+ verify(listenerCallback, never()).onTaskCreated()
+ }
+
+ @Test
+ fun onInitialized_pendingIntentChatBubble() {
+ val target = Intent(context, TestActivity::class.java)
+ val pendingIntent = PendingIntent.getActivity(context, 0, target,
+ PendingIntent.FLAG_MUTABLE)
+
+ val b = createChatBubble("key", pendingIntent)
+ bubbleTaskViewListener.setBubble(b)
+
+ assertThat(b.isChat).isTrue()
+ // Has shortcut info
+ assertThat(b.shortcutInfo).isNotNull()
+ // But it didn't use that on bubble metadata
+ assertThat(b.metadataShortcutId).isNull()
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onInitialized()
+ }
+ getInstrumentation().waitForIdleSync()
+
+ // ..so it's pending intent-based, and launches that
+ assertThat(b.isPendingIntentActive).isTrue()
+ verify(taskViewController).startActivity(any(), eq(pendingIntent), any(), any(), any())
+ }
+
+ @Test
+ fun onInitialized_shortcutChatBubble() {
+ val shortcutInfo = ShortcutInfo.Builder(context)
+ .setId("mockShortcutId")
+ .build()
+ val b = createChatBubble("key", shortcutInfo)
+ bubbleTaskViewListener.setBubble(b)
+
+ assertThat(b.isChat).isTrue()
+ assertThat(b.shortcutInfo).isNotNull()
+ // Chat bubble using a shortcut
+ assertThat(b.metadataShortcutId).isNotNull()
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onInitialized()
+ }
+ getInstrumentation().waitForIdleSync()
+
+ assertThat(b.isPendingIntentActive).isFalse()
+ verify(taskViewController).startShortcutActivity(any(), eq(shortcutInfo), any(), any())
+ }
+
+ @Test
+ fun onInitialized_appBubble() {
+ val b = createAppBubble()
+ bubbleTaskViewListener.setBubble(b)
+
+ assertThat(b.isApp).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onInitialized()
+ }
+ getInstrumentation().waitForIdleSync()
+
+ assertThat(b.isPendingIntentActive).isFalse()
+ verify(taskViewController).startActivity(any(), any(), anyOrNull(), any(), any())
+ }
+
+ @Test
+ fun onInitialized_preparingTransition() {
+ val b = createAppBubble()
+ bubbleTaskViewListener.setBubble(b)
+ taskView = Mockito.spy(taskView)
+ val preparingTransition = mock<BubbleTransitions.BubbleTransition>()
+ b.preparingTransition = preparingTransition
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onInitialized()
+ }
+ getInstrumentation().waitForIdleSync()
+
+ verify(preparingTransition).surfaceCreated()
+ }
+
+ @Test
+ fun onInitialized_destroyed() {
+ val b = createAppBubble()
+ bubbleTaskViewListener.setBubble(b)
+
+ assertThat(b.isApp).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onReleased()
+ bubbleTaskViewListener.onInitialized()
+ }
+ getInstrumentation().waitForIdleSync()
+
+ verify(taskViewController, never()).startActivity(any(), any(), anyOrNull(), any(), any())
+ }
+
+ @Test
+ fun onInitialized_initialized() {
+ val b = createAppBubble()
+ bubbleTaskViewListener.setBubble(b)
+
+ assertThat(b.isApp).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onInitialized()
+ }
+ getInstrumentation().waitForIdleSync()
+
+ reset(taskViewController)
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onInitialized()
+ }
+ // Already initialized, so no activity should be started.
+ verify(taskViewController, never()).startActivity(any(), any(), anyOrNull(), any(), any())
+ }
+
+ @Test
+ fun onTaskCreated() {
+ val b = createAppBubble()
+ bubbleTaskViewListener.setBubble(b)
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onInitialized()
+ }
+ getInstrumentation().waitForIdleSync()
+ verify(taskViewController).startActivity(any(), any(), anyOrNull(), any(), any())
+
+ val taskId = 123
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>())
+ }
+ getInstrumentation().waitForIdleSync()
+
+ verify(listenerCallback).onTaskCreated()
+ verify(expandedViewManager, never()).setNoteBubbleTaskId(any(), any())
+ assertThat(bubbleTaskViewListener.taskId).isEqualTo(taskId)
+ }
+
+ @Test
+ fun onTaskCreated_noteBubble() {
+ val b = createNoteBubble()
+ bubbleTaskViewListener.setBubble(b)
+ assertThat(b.isNote).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onInitialized()
+ }
+ getInstrumentation().waitForIdleSync()
+ verify(taskViewController).startActivity(any(), any(), anyOrNull(), any(), any())
+
+ val taskId = 123
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>())
+ }
+ getInstrumentation().waitForIdleSync()
+
+ verify(listenerCallback).onTaskCreated()
+ verify(expandedViewManager).setNoteBubbleTaskId(eq(b.key), eq(taskId))
+ assertThat(bubbleTaskViewListener.taskId).isEqualTo(taskId)
+ }
+
+ @Test
+ fun onTaskVisibilityChanged_true() {
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onTaskVisibilityChanged(1, true)
+ }
+ verify(listenerCallback).onContentVisibilityChanged(eq(true))
+ }
+
+ @Test
+ fun onTaskVisibilityChanged_false() {
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onTaskVisibilityChanged(1, false)
+ }
+ verify(listenerCallback).onContentVisibilityChanged(eq(false))
+ }
+
+ @Test
+ fun onTaskRemovalStarted() {
+ val mockTaskView = mock<TaskView>()
+ bubbleTaskView = BubbleTaskView(mockTaskView, mainExecutor)
+
+ bubbleTaskViewListener =
+ BubbleTaskViewListener(
+ context,
+ bubbleTaskView,
+ parentView,
+ expandedViewManager,
+ listenerCallback
+ )
+
+ val b = createAppBubble()
+ bubbleTaskViewListener.setBubble(b)
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onInitialized()
+ }
+ getInstrumentation().waitForIdleSync()
+ verify(mockTaskView).startActivity(any(), anyOrNull(), any(), any())
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onTaskRemovalStarted(1)
+ }
+
+ verify(expandedViewManager).removeBubble(eq(b.key), eq(Bubbles.DISMISS_TASK_FINISHED))
+ verify(mockTaskView).release()
+ assertThat(parentView.lastRemovedView).isEqualTo(mockTaskView)
+ assertThat(bubbleTaskViewListener.taskView).isNull()
+ verify(listenerCallback).onTaskRemovalStarted()
+ }
+
+ @Test
+ fun onBackPressedOnTaskRoot_expanded() {
+ val taskId = 123
+ whenever(expandedViewManager.isStackExpanded()).doReturn(true)
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>())
+ bubbleTaskViewListener.onBackPressedOnTaskRoot(taskId)
+ }
+ verify(listenerCallback).onBackPressed()
+ }
+
+ @Test
+ fun onBackPressedOnTaskRoot_notExpanded() {
+ val taskId = 123
+ whenever(expandedViewManager.isStackExpanded()).doReturn(false)
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>())
+ bubbleTaskViewListener.onBackPressedOnTaskRoot(taskId)
+ }
+ verify(listenerCallback, never()).onBackPressed()
+ }
+
+ @Test
+ fun onBackPressedOnTaskRoot_taskIdMissMatch() {
+ val taskId = 123
+ whenever(expandedViewManager.isStackExpanded()).doReturn(true)
+
+ getInstrumentation().runOnMainSync {
+ bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>())
+ bubbleTaskViewListener.onBackPressedOnTaskRoot(42)
+ }
+ verify(listenerCallback, never()).onBackPressed()
+ }
+
+ @Test
+ fun setBubble_isNew() {
+ val b = createAppBubble()
+ val isNew = bubbleTaskViewListener.setBubble(b)
+ assertThat(isNew).isTrue()
+ }
+
+ @Test
+ fun setBubble_launchContentChanged() {
+ val target = Intent(context, TestActivity::class.java)
+ val pendingIntent = PendingIntent.getActivity(
+ context, 0, target,
+ PendingIntent.FLAG_MUTABLE
+ )
+
+ val b = createChatBubble("key", pendingIntent)
+ var isNew = bubbleTaskViewListener.setBubble(b)
+ // First time bubble is set, so it is "new"
+ assertThat(isNew).isTrue()
+
+ val b2 = createChatBubble("key", pendingIntent)
+ isNew = bubbleTaskViewListener.setBubble(b2)
+ // Second time bubble is set & it uses same type of launch content, not "new"
+ assertThat(isNew).isFalse()
+
+ val shortcutInfo = ShortcutInfo.Builder(context)
+ .setId("mockShortcutId")
+ .build()
+ val b3 = createChatBubble("key", shortcutInfo)
+ // bubble is using different content, so it is "new"
+ isNew = bubbleTaskViewListener.setBubble(b3)
+ assertThat(isNew).isTrue()
+ }
+
+ private fun createAppBubble(): Bubble {
+ val target = Intent(context, TestActivity::class.java)
+ target.setPackage(context.packageName)
+ return Bubble.createAppBubble(target, mock<UserHandle>(), mock<Icon>(),
+ mainExecutor, bgExecutor)
+ }
+
+ private fun createNoteBubble(): Bubble {
+ val target = Intent(context, TestActivity::class.java)
+ target.setPackage(context.packageName)
+ return Bubble.createNotesBubble(target, mock<UserHandle>(), mock<Icon>(),
+ mainExecutor, bgExecutor)
+ }
+
+ private fun createChatBubble(key: String, shortcutInfo: ShortcutInfo): Bubble {
+ return Bubble(
+ key,
+ shortcutInfo,
+ 0 /* desiredHeight */,
+ 0 /* desiredHeightResId */,
+ "title",
+ -1 /*taskId */,
+ null /* locusId */, true /* isdismissabel */,
+ mainExecutor, bgExecutor, mock<BubbleMetadataFlagListener>()
+ )
+ }
+
+ private fun createChatBubble(key: String, pendingIntent: PendingIntent): Bubble {
+ val metadata = Notification.BubbleMetadata.Builder(
+ pendingIntent,
+ Icon.createWithResource(context, R.drawable.bubble_ic_create_bubble)
+ ).build()
+ val shortcutInfo = ShortcutInfo.Builder(context)
+ .setId("shortcutId")
+ .build()
+ val notification: Notification =
+ Notification.Builder(context, key)
+ .setSmallIcon(mock<Icon>())
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("title")
+ .setContentText("content")
+ .setBubbleMetadata(metadata)
+ .build()
+ val sbn = mock<StatusBarNotification>()
+ val ranking = mock<Ranking>()
+ whenever(sbn.getNotification()).thenReturn(notification)
+ whenever(sbn.getKey()).thenReturn(key)
+ whenever(ranking.getConversationShortcutInfo()).thenReturn(shortcutInfo)
+ val entry = BubbleEntry(sbn, ranking, true, false, false, false)
+ return Bubble(
+ entry, mock<BubbleMetadataFlagListener>(), null, mainExecutor,
+ bgExecutor
+ )
+ }
+
+ /**
+ * FrameLayout that immediately runs any runnables posted to it and tracks view removals.
+ */
+ class ViewPoster(context: Context) : FrameLayout(context) {
+
+ lateinit var lastRemovedView: View
+
+ override fun post(r: Runnable): Boolean {
+ r.run()
+ return true
+ }
+
+ override fun removeView(v: View) {
+ super.removeView(v)
+ lastRemovedView = v
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
index 8d7e5fd95957..d50a14cf5dae 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
@@ -18,23 +18,28 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/maximize_menu"
android:layout_width="wrap_content"
- android:layout_height="@dimen/desktop_mode_maximize_menu_height"
+ android:layout_height="wrap_content"
android:background="@drawable/desktop_mode_maximize_menu_background"
android:elevation="1dp">
<LinearLayout
android:id="@+id/container"
android:layout_width="wrap_content"
- android:layout_height="@dimen/desktop_mode_maximize_menu_height"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
- android:padding="16dp"
+ android:paddingHorizontal="12dp"
+ android:paddingVertical="16dp"
+ android:measureWithLargestChild="true"
android:gravity="center">
<LinearLayout
android:id="@+id/maximize_menu_immersive_toggle_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp">
<Button
android:layout_width="94dp"
@@ -44,21 +49,22 @@
android:stateListAnimator="@null"
android:importantForAccessibility="yes"
android:contentDescription="@string/desktop_mode_maximize_menu_immersive_button_text"
- android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
android:alpha="0"/>
<TextView
android:id="@+id/maximize_menu_immersive_toggle_button_text"
- android:layout_width="94dp"
- android:layout_height="18dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:textSize="11sp"
- android:layout_marginBottom="76dp"
+ android:lineHeight="16sp"
android:gravity="center"
android:fontFamily="google-sans-text"
+ android:textFontWeight="500"
android:importantForAccessibility="no"
android:text="@string/desktop_mode_maximize_menu_immersive_button_text"
android:textColor="@androidprv:color/materialColorOnSurface"
+ android:singleLine="true"
android:alpha="0"/>
</LinearLayout>
@@ -66,7 +72,11 @@
android:id="@+id/maximize_menu_size_toggle_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:gravity="center_horizontal"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp">
<Button
android:layout_width="94dp"
@@ -81,15 +91,17 @@
<TextView
android:id="@+id/maximize_menu_size_toggle_button_text"
- android:layout_width="94dp"
- android:layout_height="18dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:textSize="11sp"
- android:layout_marginBottom="76dp"
+ android:lineHeight="16sp"
android:gravity="center"
android:fontFamily="google-sans-text"
+ android:textFontWeight="500"
android:importantForAccessibility="no"
android:text="@string/desktop_mode_maximize_menu_maximize_text"
android:textColor="@androidprv:color/materialColorOnSurface"
+ android:singleLine="true"
android:alpha="0"/>
</LinearLayout>
@@ -97,7 +109,11 @@
android:id="@+id/maximize_menu_snap_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:gravity="center_horizontal"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp">
<LinearLayout
android:id="@+id/maximize_menu_snap_menu_layout"
android:layout_width="wrap_content"
@@ -106,7 +122,6 @@
android:padding="4dp"
android:background="@drawable/desktop_mode_maximize_menu_layout_background"
android:layout_marginBottom="4dp"
- android:layout_marginStart="8dp"
android:alpha="0">
<Button
android:id="@+id/maximize_menu_snap_left_button"
@@ -131,16 +146,17 @@
</LinearLayout>
<TextView
android:id="@+id/maximize_menu_snap_window_text"
- android:layout_width="94dp"
- android:layout_height="18dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:textSize="11sp"
- android:layout_marginBottom="76dp"
- android:layout_gravity="center"
+ android:lineHeight="16sp"
android:gravity="center"
android:importantForAccessibility="no"
android:fontFamily="google-sans-text"
+ android:textFontWeight="500"
android:text="@string/desktop_mode_maximize_menu_snap_text"
android:textColor="@androidprv:color/materialColorOnSurface"
+ android:singleLine="true"
android:alpha="0"/>
</LinearLayout>
</LinearLayout>
@@ -150,6 +166,6 @@
<View
android:id="@+id/maximize_menu_overlay"
android:layout_width="match_parent"
- android:layout_height="@dimen/desktop_mode_maximize_menu_height"/>
+ android:layout_height="match_parent"/>
</FrameLayout>
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 13e5f34e1586..5444c26e9ec9 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Links 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Links 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Volskerm regs"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Ruil apps om"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Volskerm bo"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Bo 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bo 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Stel terug"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Spring na links"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Spring na regs"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Verander grootte van linkerkantse venster"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Verander grootte van regterkantse venster"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimeer of stel venstergrootte terug"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Gaan na deelskermmodus"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Gaan na werkskermvenstermodus"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Verander grootte van linkerkantse venster"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Verander grootte van regterkantse venster"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimeer of stel venstergrootte terug"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimeer of stel venstergrootte terug"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimeer appvenster"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Maak By Verstek Oop-instellings"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Kies hoe om webskakels vir hierdie app oop te maak"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In die app"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 14a79aa8475b..f3bc29d95673 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ግራ 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ግራ 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"የቀኝ ሙሉ ማያ ገፅ"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"መተግበሪያዎችን ይቀያይሩ"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"የላይ ሙሉ ማያ ገፅ"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ከላይ 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ከላይ 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ወደነበረበት መልስ"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ወደ ግራ አሳድግ"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ወደ ቀኝ አሳድግ"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"የመተግበሪያ መስኮትን ወደ ግራ መጠን ቀይር"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"የመተግበሪያ መስኮትን ወደ ቀኝ መጠን ቀይር"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ወደ የተከፈለ ማያ ገፅ ሁነታ ግባ"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ወደ የዴስክቶፕ መስኮት ሁነታ ግባ"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"መስኮትን ወደ ግራ መጠን ቀይር"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"መስኮትን ወደ ቀኝ መጠን ቀይር"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"የመተግበሪያ መስኮትን አሳንስ"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"በነባሪ ቅንብሮች ክፈት"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ለዚህ የድር መተግበሪያ አገናኙን እንዴት እንደሚከፍቱ ይምረጡ"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"በመተግበሪያው ውስጥ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 9a6869a64f3f..60f27cfdee91 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ضبط حجم النافذة اليسرى ليكون ٥٠%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ضبط حجم النافذة اليسرى ليكون ٣٠%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"عرض النافذة اليمنى بملء الشاشة"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"تبديل التطبيقات"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"عرض النافذة العلوية بملء الشاشة"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ضبط حجم النافذة العلوية ليكون ٧٠%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ضبط حجم النافذة العلوية ليكون ٥٠%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"استعادة"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"المحاذاة إلى اليسار"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"المحاذاة إلى اليمين"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"تغيير حجم نافذة التطبيق بمحاذاتها إلى اليمين"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"تغيير حجم نافذة التطبيق بمحاذاتها إلى اليسار"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"تكبير حجم النافذة أو استعادته"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"تفعيل \"وضع تقسيم الشاشة\""</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"تفعيل وضع عرض المحتوى في النافذة الحالية على سطح المكتب"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"تغيير حجم النافذة بمحاذاتها إلى اليمين"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"تغيير حجم النافذة بمحاذاتها إلى اليسار"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"تكبير حجم النافذة أو استعادته"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"تكبير حجم النافذة أو استعادته"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"تصغير نافذة التطبيق"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"إعدادات الفتح تلقائيًا"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اختيار طريقة فتح روابط الويب لهذا التطبيق"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"في التطبيق"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 5181930edf57..aced354ac826 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sol 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sol 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağ tam ekran"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Tətbiqləri dəyişin"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yuxarı tam ekran"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yuxarı 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yuxarı 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Bərpa edin"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Sola tərəf çəkin"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Sağa tərəf çəkin"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Tətbiq pəncərəsinin ölçüsünü sola dəyişin"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Tətbiq pəncərəsinin ölçüsünü sağa dəyişin"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Bölünmüş ekran rejiminə daxil olun"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masaüstü pəncərə rejiminə daxil olun"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pəncərə ölçüsünü sola dəyişin"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pəncərə ölçüsünü sağa dəyişin"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Tətbiq pəncərəsini kiçildin"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Defolt ayarlarla açın"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu tətbiq üçün veb-linklərin necə açılacağını seçin"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Tətbiqdə"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 92580d39f12c..b07c61258f4e 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -125,11 +125,11 @@
<string name="float_button_text" msgid="9221657008391364581">"Plutajuće"</string>
<string name="select_text" msgid="5139083974039906583">"Izaberite"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string>
- <string name="open_in_browser_text" msgid="9181692926376072904">"Otvorite u pregledaču"</string>
+ <string name="open_in_browser_text" msgid="9181692926376072904">"Otvori u pregledaču"</string>
<string name="open_in_app_text" msgid="2874590745116268525">"Otvorite u aplikaciji"</string>
<string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljajte prozorima"</string>
- <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promenite razmeru"</string>
+ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promeni razmeru"</string>
<string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvorite meni"</string>
@@ -138,7 +138,7 @@
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija ne može da se premesti ovde"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Imerzivne"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vrati"</string>
- <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Uvećajte"</string>
+ <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Uvećaj"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Vratite"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Prikačite levo"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Prikačite desno"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index e7feb5b6fa8c..fcc4d83baf75 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ляв екран: 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ляв екран: 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десен екран: Показване на цял екран"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Размяна на приложенията"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горен екран: Показване на цял екран"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горен екран: 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горен екран: 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Възстановяване"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Прилепване наляво"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Прилепване надясно"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Преоразмеряване на прозореца на приложението наляво"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Преоразмеряване на прозореца на приложението надясно"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Увеличаване или възстановяване на размера на прозореца"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Активиране на режима за разделен екран"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Активиране на режима за настолни компютри"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Преоразмеряване на прозореца наляво"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Преоразмеряване на прозореца надясно"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Увеличаване или възстановяване на размера на прозореца"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Увеличаване или възстановяване на размера на прозореца"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Намаляване на прозореца на приложението"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Отваряне на настройките по подразбиране"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Изберете как да се отварят уеб връзките за това приложение"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"В приложението"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index f4f887771fd9..b2c435e5ef0e 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"৫০% বাকি আছে"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"৩০% বাকি আছে"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ডান দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"অ্যাপ পাল্টান"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"উপর দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"শীর্ষ ৭০%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ ৫০%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ফিরিয়ে আনুন"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"বাঁদিকে স্ন্যাপ করুন"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ডানদিকে স্ন্যাপ করুন"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"বাঁদিকে অ্যাপ উইন্ডো রিসাইজ করুন"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ডানদিকে অ্যাপ উইন্ডো রিসাইজ করুন"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"স্প্লিট স্ক্রিন মোডে প্রবেশ করুন"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ডেস্কটপ উইন্ডোইং মোডে প্রবেশ করুন"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"বাঁদিকে উইন্ডো রিসাইজ করুন"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ডানদিকে উইন্ডো রিসাইজ করুন"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"অ্যাপ উইন্ডো ছোট করুন"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"ডিফল্ট হিসেবে থাকা সেটিংস খুলুন"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"এই অ্যাপের জন্য কীভাবে ওয়েব লিঙ্ক খুলবেন তা বেছে নিন"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"অ্যাপের মধ্যে"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 12e4fc2700ed..8c1619ce925c 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -43,7 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevo 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Lijevo 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desno cijeli ekran"</string>
- <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Zamijeni aplikacije"</string>
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Zamjena aplikacija"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Gore cijeli ekran"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gore 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gore 50%"</string>
@@ -138,20 +138,20 @@
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ne možete premjestiti aplikaciju ovdje"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Uvjerljivo"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vraćanje"</string>
- <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziranje"</string>
+ <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziraj"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Vraćanje"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Pomicanje ulijevo"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Pomicanje udesno"</string>
- <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Promijeni veličinu prozora aplikacije ulijevo"</string>
- <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Promijeni veličinu prozora aplikacije udesno"</string>
- <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimiziraj ili vrati veličinu prozora"</string>
- <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Pokreni način podijeljenog zaslona"</string>
- <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Pokreni način prikaza u prozorima na računalu"</string>
- <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promijeni veličinu prozora ulijevo"</string>
- <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promijeni veličinu prozora udesno"</string>
- <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziraj ili vrati veličinu prozora"</string>
- <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimiziraj ili vrati veličinu prozora"</string>
- <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimiziraj prozor aplikacije"</string>
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Promjena veličine prozora aplikacije lijevo"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Promjena veličine prozora aplikacije desno"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimiziranje ili vraćanje veličine prozora"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Pokretanje načina rada podijeljenog ekrana"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Pokretanje načina rada s prozorima na radnoj površini"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promjena veličine prozora i poravnanje lijevo"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promjena veličine prozora i poravnanje desno"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziranje ili vraćanje veličine prozora"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimiziranje ili vraćanje veličine prozora"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimiziranje prozora aplikacije"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvaranje prema zadanim postavkama"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja web linkova za ovu aplikaciju"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 1623954d1d7c..37802f4c7f94 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pantalla esquerra al 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pantalla esquerra al 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla dreta completa"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Canvia les aplicacions"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Pantalla superior al 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Pantalla superior al 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restaura"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ajusta a l\'esquerra"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ajusta a la dreta"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Canvia la mida de la finestra de l\'aplicació a l\'esquerra"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Canvia la mida de la finestra de l\'aplicació a la dreta"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximitza o restaura la mida de la finestra"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Entra al mode de pantalla dividida"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Entra al mode d\'enfinestrament a l\'escriptori"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Canvia la mida de la finestra a l\'esquerra"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Canvia la mida de la finestra a la dreta"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximitza o restaura la mida de la finestra"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximitza o restaura la mida de la finestra"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimitza la finestra de l\'aplicació"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Configuració d\'obertura predeterminada"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Tria com vols obrir els enllaços web per a aquesta aplicació"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"A l\'aplicació"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index f6ac59ca24b7..c4514eb4ce8d 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % vlevo"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % vlevo"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pravá část na celou obrazovku"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Zaměnit aplikace"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Horní část na celou obrazovku"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % nahoře"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % nahoře"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Obnovit"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Přichytit vlevo"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Přichytit vpravo"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Změnit velikost okna aplikace vlevo"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Změnit velikost okna aplikace vpravo"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximalizovat nebo obnovit velikost okna"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Přechod do režimu rozdělené obrazovky"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Přejít do režimu okenního systému pro počítače"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Přichytit okno vlevo"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Přichytit okno vpravo"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximalizovat nebo obnovit velikost okna"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximalizovat nebo obnovit velikost okna"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimalizovat okno aplikace"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Otevírat podle výchozího nastavení"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Určete, jak se v této aplikaci mají otevírat webové odkazy"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikaci"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index d7ee8a0cf8c3..7b21719bc880 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % links"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % links"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Vollbild rechts"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Apps austauschen"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Vollbild oben"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % oben"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % oben"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Wiederherstellen"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Links andocken"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Rechts andocken"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Größe des linken App-Fensters anpassen"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Größe des rechten App-Fensters anpassen"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Fenstergröße maximieren oder wiederherstellen"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Splitscreen-Modus aktivieren"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Desktop-Fenstermodus aktivieren"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Fenstergröße links anpassen"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Fenstergröße rechts anpassen"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Fenstergröße maximieren oder wiederherstellen"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Fenstergröße maximieren oder wiederherstellen"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"App-Fenster minimieren"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Einstellungen für die Option „Standardmäßig öffnen“"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Festlegen, wie Weblinks für diese App geöffnet werden"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In der App"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 4ba68b4fc9db..eb45a31c5d8a 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Αριστερή 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Αριστερή 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Δεξιά πλήρης οθόνη"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Εναλλαγή εφαρμογών"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Πάνω πλήρης οθόνη"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Πάνω 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Πάνω 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Επαναφορά"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Κούμπωμα αριστερά"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Κούμπωμα δεξιά"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Αλλαγή μεγέθους παραθύρου εφαρμογής αριστερά"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Αλλαγή μεγέθους παραθύρου εφαρμογής δεξιά"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Είσοδος στη λειτουργία διαχωρισμού οθόνης"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Είσοδος στη λειτουργία προσαρμογής σε παράθυρο υπολογιστή"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Αλλαγή μεγέθους παραθύρου προς τα αριστερά"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Αλλαγή μεγέθους παραθύρου προς τα δεξιά"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Ελαχιστοποίηση παραθύρου εφαρμογής"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Άνοιγμα ρυθμίσεων από προεπιλογή"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Επιλογή τρόπου ανοίγματος συνδέσμων ιστού για την εφαρμογή"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Στην εφαρμογή"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 8b1a14f66195..8dc27dabfc2c 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Swap apps"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restore"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximise or restore window size"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split-screen mode"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximise or restore window size"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimise app window"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 8b1a14f66195..8dc27dabfc2c 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Swap apps"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restore"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximise or restore window size"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split-screen mode"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximise or restore window size"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimise app window"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 8b1a14f66195..8dc27dabfc2c 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Swap apps"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restore"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximise or restore window size"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split-screen mode"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximise or restore window size"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimise app window"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index f36135e1febd..dd9635dccfcb 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Izquierda 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla derecha completa"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Cambiar aplicaciones"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Superior 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restaurar"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Acoplar a la izquierda"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Acoplar a la derecha"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Cambiar tamaño de la ventana de la aplicación izquierda"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Cambiar tamaño de la ventana de la aplicación derecha"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizar o restaurar tamaño de la ventana"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Activar modo Pantalla dividida"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Activar modo Escritorio basado en ventanas"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Cambiar tamaño de la ventana a la izquierda"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Cambiar tamaño de la ventana a la derecha"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar o restaurar tamaño de la ventana"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximizar o restaurar tamaño de la ventana"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizar ventana de la aplicación"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir con los ajustes predeterminados"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Elige cómo quieres abrir los enlaces web de esta aplicación"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"En la aplicación"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index b77d0eb642f7..9898af0c394d 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ezarri ezkerraldea % 50en"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ezarri ezkerraldea % 30en"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ezarri eskuinaldea pantaila osoan"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Aldatu aplikazioz"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ezarri goialdea pantaila osoan"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Ezarri goialdea % 70en"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ezarri goialdea % 50en"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Leheneratu"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ezarri ezkerrean"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ezarri eskuinean"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Aldatu aplikazioaren leihoaren tamaina eta eraman ezkerrera"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Aldatu aplikazioaren leihoaren tamaina eta eraman eskuinera"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizatu edo leheneratu leihoaren tamaina"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Sartu pantaila zatituaren moduan"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Sartu ordenagailuan leihoak erabiltzeko moduan"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Aldatu leihoaren tamaina eta eraman ezkerrera"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Aldatu leihoaren tamaina eta eraman eskuinera"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizatu edo leheneratu leihoaren tamaina"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximizatu edo leheneratu leihoaren tamaina"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizatu aplikazioaren leihoa"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Modu lehenetsian irekitzearen ezarpenak"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Aukeratu nola ireki sareko estekak aplikazio honetan"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Aplikazioan"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 06ff6e74322c..b23c833fa453 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasen 50 %"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vasen 30 %"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Oikea koko näytölle"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Vaihda sovellusta"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yläosa koko näytölle"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yläosa 70 %"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yläosa 50 %"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Palauta"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Siirrä vasemmalle"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Siirrä oikealle"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Muuta vasemmanpuoleisen sovellusikkunan kokoa"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Muuta oikeanpuoleisen sovellusikkunan kokoa"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Suurenna ikkuna tai palauta ikkunan koko"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Avaa kahtia jaettu näyttö"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Siirry työpöydän ikkunointitilaan"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Muuta vasemmanpuoleisen ikkunan kokoa"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Muuta vasemmanpuoleisen ikkunan kokoa"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Suurenna ikkuna tai palauta ikkunan koko"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Suurenna ikkuna tai palauta ikkunan koko"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Pienennä sovellusikkuna"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Avaa oletusasetusten mukaan"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Valitse, miten verkkolinkit avataan tässä sovelluksessa"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Sovelluksessa"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 08ff1d35a8c7..34b5b0acf753 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % à la gauche"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % à la gauche"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Plein écran à la droite"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Permuter des applis"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Plein écran dans le haut"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % dans le haut"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % dans le haut"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restaurer"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Épingler à gauche"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Épingler à droite"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionner la fenêtre de l\'appli à gauche"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionner la fenêtre de l\'appli à droite"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Agrandir ou restaurer la taille de la fenêtre"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Entrer en mode Écran divisé"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Entrer en mode Fenêtrage bureau"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Agrandir ou restaurer la taille de la fenêtre"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Réduire la fenêtre de l\'appli"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Ouvrir les paramètres par défaut"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choisissez comment ouvrir les liens Web pour cette appli"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Dans l\'appli"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 9ced5c7bafd4..be41bba34772 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Écran de gauche à 50 %"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Écran de gauche à 30 %"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Écran de droite en plein écran"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Échanger les applis"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Écran du haut en plein écran"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Écran du haut à 70 %"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Écran du haut à 50 %"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restaurer"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ancrer à gauche"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ancrer à droite"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionner la fenêtre de l\'appli vers la gauche"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionner la fenêtre de l\'appli vers la droite"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Agrandir ou restaurer la taille de la fenêtre"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Passer en mode Écran partagé"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Activer le mode fenêtrage du bureau"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Agrandir ou restaurer la taille de la fenêtre"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Réduire la fenêtre de l\'application"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Ouvrir les paramètres par défaut"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choisir comment ouvrir les liens Web pour cette appli"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Dans l\'application"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index d8c422fd1bd2..dcd57385809f 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ડાબે 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ડાબે 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"જમણી સ્ક્રીન સ્ક્રીન"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ઍપને સ્વૉપ કરો"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"શીર્ષ પૂર્ણ સ્ક્રીન"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"શીર્ષ 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"શીર્ષ 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"રિસ્ટોર કરો"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ડાબે સ્નૅપ કરો"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"જમણે સ્નૅપ કરો"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ડાબી બાજુથી ઍપની વિન્ડોનું કદ બદલો"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"જમણી બાજુથી ઍપની વિન્ડોનું કદ બદલો"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"વિન્ડોનું કદ મહત્તમ કરો અથવા રિસ્ટોર કરો"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"સ્ક્રીન-વિભાજન મોડ દાખલ કરો"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ડેસ્કટૉપ વિન્ડો મોડ દાખલ કરો"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ડાબી બાજુ વિન્ડોનું કદ બદલો"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"જમણી બાજુ વિન્ડોનું કદ બદલો"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"વિન્ડોનું કદ મહત્તમ કરો અથવા રિસ્ટોર કરો"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"વિન્ડોનું કદ મહત્તમ કરો અથવા રિસ્ટોર કરો"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ઍપની વિન્ડોને નાની કરો"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"\'ડિફૉલ્ટ તરીકે ખોલો\' સેટિંગ"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"આ ઍપ માટે વેબ લિંક ખોલવાની રીત પસંદ કરો"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ઍપમાં"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index f8215afb1c05..4bf2d92c1860 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बाईं स्क्रीन को 50% बनाएं"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बाईं स्क्रीन को 30% बनाएं"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दाईं स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ऐप्लिकेशन स्वैप करें"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ऊपर की स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ऊपर की स्क्रीन को 70% बनाएं"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ऊपर की स्क्रीन को 50% बनाएं"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"पहले जैसा करें"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"बाईं ओर स्नैप करें"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"दाईं ओर स्नैप करें"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ऐप्लिकेशन विंडो का साइज़ बाईं ओर से बदलें"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ऐप्लिकेशन विंडो का साइज़ दाईं ओर से बदलें"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"स्प्लिट स्क्रीन मोड में चालू करें"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"डेस्कटॉप विंडो मोड में जाएं"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विंडो का साइज़ बाईं ओर से बदलें"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विंडो का साइज़ दाईं ओर से बढ़ाएं"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ऐप्लिकेशन की विंडो को छोटा करें"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफ़ॉल्ट सेटिंग के हिसाब से खोलें"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"इस ऐप्लिकेशन के लिए वेब लिंक खोलने का तरीका चुनें"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ऐप्लिकेशन में"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index 76e7579232d9..546a465c8699 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Bal oldali 50%-ra"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Bal oldali 30%-ra"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Jobb oldali teljes képernyőre"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Váltás az alkalmazások között"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Felső teljes képernyőre"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Felső 70%-ra"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Felső 50%-ra"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Visszaállítás"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Balra igazítás"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Jobbra igazítás"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Alkalmazásablak átméretezése balra"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Alkalmazásablak átméretezése jobbra"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Ablak teljes méretre állítása vagy visszaállítása"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Belépés osztott képernyős módba"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Asztali ablakkezelési mód indítása"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ablak átméretezése balra"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ablak átméretezése jobbra"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ablak teljes méretre állítása vagy visszaállítása"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Ablak teljes méretre állítása vagy visszaállítása"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Alkalmazásablak kis méretre állítása"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Alapértelmezett beállítások megnyitása"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Az app webes linkjeinek megnyitásához használt módszer"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Az alkalmazásban"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 0eb75c79e4b8..39a395f9add1 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ձախ էկրանը՝ 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ձախ էկրանը՝ 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Աջ էկրանը՝ լիաէկրան"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Հավելվածները տեղերով փոխել"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Վերևի էկրանը՝ լիաէկրան"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Վերևի էկրանը՝ 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Վերևի էկրանը՝ 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Վերականգնել"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ամրացնել ձախ կողմում"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ամրացնել աջ կողմում"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ձգել հավելվածի պատուհանը դեպի ձախ"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ձգել հավելվածի պատուհանը դեպի աջ"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Մտնել էկրանի տրոհման ռեժիմ"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Մտնել համակարգչի ռեժիմ"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ձգել պատուհանը դեպի ձախ"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ձգել պատուհանը դեպի աջ"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Ծալել հավելվածի պատուհանը"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Բացել կարգավորումներն ըստ կանխադրման"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Ընտրեք՝ ինչպես բացել այս հավելվածի վեբ հղումները"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Հավելվածում"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 813e9783f336..09ce5257c56e 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kiri 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Layar penuh di kanan"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Ganti Aplikasi"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Layar penuh di atas"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Atas 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Pulihkan"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Maksimalkan ke kiri"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Maksimalkan ke kanan"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ubah ukuran jendela aplikasi ke kiri"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ubah ukuran jendela aplikasi ke kanan"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimalkan atau pulihkan ukuran jendela"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Masuk ke mode layar terpisah"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masuk ke mode windowing desktop"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ubah ukuran jendela ke kiri"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ubah ukuran jendela ke kanan"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimalkan atau pulihkan ukuran jendela"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimalkan atau pulihkan ukuran jendela"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimalkan jendela aplikasi"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Buka dengan setelan default"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pilih cara membuka link web untuk aplikasi ini"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Di aplikasi"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 1cd89a615cb2..b164b1131ad2 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"שמאלה 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"שמאלה 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"מסך ימני מלא"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"מעבר בין אפליקציות"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"מסך עליון מלא"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"עליון 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"עליון 50%"</string>
@@ -130,7 +129,7 @@
<string name="open_in_app_text" msgid="2874590745116268525">"פתיחה באפליקציה"</string>
<string name="new_window_text" msgid="6318648868380652280">"חלון חדש"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"ניהול החלונות"</string>
- <string name="change_aspect_ratio_text" msgid="9104456064548212806">"שינוי של יחס גובה-רוחב"</string>
+ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"שינוי יחס הגובה-רוחב"</string>
<string name="close_text" msgid="4986518933445178928">"סגירה"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"פתיחת התפריט"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"שחזור"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"הצמדה לשמאל"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"הצמדה לימין"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"שינוי הגודל של חלון האפליקציה שמשמאל"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"שינוי הגודל של חלון האפליקציה שמימין"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"שחזור של גודל החלון או הגדלת החלון"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"כניסה למצב מסך מפוצל"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"כניסה למצב שינוי הגודל של החלונות בממשק המחשב"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"שינוי גודל החלון שמשמאל"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"שינוי גודל החלון שמימין"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"שחזור של גודל החלון או הגדלת החלון"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"שחזור של גודל החלון או הגדלת החלון"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"מזעור החלון של האפליקציה"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"הגדרות לפתיחה כברירת מחדל"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"כאן בוחרים איך לפתוח באפליקציה הזו קישורים לדפי אינטרנט"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"באפליקציה"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 02e0f320eea6..1be19af9b372 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"მარცხენა ეკრანი — 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"მარცხენა ეკრანი — 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"მარჯვენა ნაწილის სრულ ეკრანზე გაშლა"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"აპების გადართვა"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ზედა ნაწილის სრულ ეკრანზე გაშლა"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ზედა ეკრანი — 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ზედა ეკრანი — 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"აღდგენა"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"მარცხნივ გადატანა"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"მარჯვნივ გადატანა"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"აპის მარცხენა ფანჯრის ზომის შეცვლა"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"აპის მარჯვენა ფანჯრის ზომის შეცვლა"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"გაყოფილი ეკრანის რეჟიმში შესვლა"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"დესკტოპის ფანჯრის რეჟიმში შესვლა"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ფანჯრის ზომის შეცვლა მარცხნივ"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ფანჯრის ზომის შეცვლა მარჯვნივ"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"აპის ფანჯრის ზომის შემცირება"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"პარამეტრების ნაგულისხმევად გახსნა"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ამ აპისთვის ვებ ბმულების გახსნის წესის არჩევა"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"აპში"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 61c331df7598..5bd85191ec65 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% сол жақта"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% сол жақта"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жағын толық экранға шығару"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Қолданбаларды ауыстыру"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Жоғарғы жағын толық экранға шығару"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% жоғарғы жақта"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% жоғарғы жақта"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Қалпына келтіру"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Солға тіркеу"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Оңға тіркеу"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Қолданба терезесінің өлшемін сол жақтан өзгерту"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Қолданба терезесінің өлшемін оң жақтан өзгерту"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Терезе өлшемін ұлғайту не қалпына келтіру"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Экранды бөлу режиміне өту"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Жұмыс үстелінің терезе режиміне өту"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезе өлшемін сол жаққа өзгерту"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезе өлшемін оң жаққа өзгерту"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезе өлшемін ұлғайту не қалпына келтіру"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Терезе өлшемін ұлғайту не қалпына келтіру"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Қолданба терезесін кішірейту"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Әдепкісінше ашу параметрлері"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Осы қолданбадағы веб-сілтемелерді ашу жолын таңдаңыз"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Қолданбада"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 13c700952609..65add57a9e6b 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"왼쪽 화면 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"왼쪽 화면 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"오른쪽 화면 전체화면"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"앱 전환"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"위쪽 화면 전체화면"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"위쪽 화면 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"위쪽 화면 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"복원"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"왼쪽으로 맞추기"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"오른쪽으로 맞추기"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"앱 창 크기 왼쪽으로 조절"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"앱 창 크기 오른쪽으로 조절"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"창 최대화 또는 크기 복원"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"화면 분할 모드 시작"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"데스크톱 창 모드 시작"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"창 크기 왼쪽으로 조절"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"창 크기 오른쪽으로 조절"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"창 최대화 또는 크기 복원"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"창 최대화 또는 크기 복원"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"앱 창 최소화"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"기본값으로 열기 설정"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"이 앱에서 웹 링크를 여는 방법을 선택하세요"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"앱에서"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index eb990f142da8..96c2226daf58 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Сол жактагы экранды 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Сол жактагы экранды 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жактагы экранды толук экран режимине өткөрүү"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Колдонмолорду алмаштыруу"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Үстүнкү экранды толук экран режимине өткөрүү"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Үстүнкү экранды 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Үстүнкү экранды 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Калыбына келтирүү"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Солго жылдыруу"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Оңго жылдыруу"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Колдонмонун терезесинин өлчөмүн солго өзгөртүү"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Колдонмонун терезесинин өлчөмүн оңго өзгөртүү"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Экранды бөлүү режимине өтүү"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Иш тактанын терезелери режимине өтүү"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезенин өлчөмүн солго өзгөртүү"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезенин өлчөмүн оңго өзгөртүү"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Колдонмонун терезесин кичирейтүү"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Демейки шартта ачылуучу шилтемелердин параметрлери"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Колдонмодо шилтемелер кантип ачыларын тандаңыз"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Колдонмодо"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 50164c081bb4..9337efc92606 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ຊ້າຍ 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ຊ້າຍ 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ເຕັມໜ້າຈໍຂວາ"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ສະຫຼັບແອັບ"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ເຕັມໜ້າຈໍເທິງສຸດ"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ເທິງສຸດ 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ເທິງສຸດ 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ກູ້ຄືນ"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ແນບຊ້າຍ"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ແນບຂວາ"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ປັບຂະໜາດໜ້າຈໍແອັບໄປທາງຊ້າຍ"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ປັບຂະໜາດໜ້າຈໍແອັບໄປທາງຂວາ"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ເຂົ້າສູ່ໂໝດແບ່ງໜ້າຈໍ"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ເຂົ້າສູ່ໂໝດໜ້າຈໍເດັສທັອບ"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ປັບຂະໜາດໜ້າຈໍໄປທາງຊ້າຍ"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ປັບຂະໜາດໜ້າຈໍໄປທາງຂວາ"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ຫຍໍ້ໜ້າຈໍແອັບ"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"ເປີດຕາມການຕັ້ງຄ່າເລີ່ມຕົ້ນ"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ເລືອກວິທີເປີດລິ້ງເວັບສຳລັບແອັບນີ້"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ໃນແອັບ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index a5547b0f71ea..24a969bc8c1b 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pa kreisi 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pa kreisi 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Labā daļa pa visu ekrānu"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Apmainīt lietotnes"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Augšdaļa pa visu ekrānu"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Augšdaļa 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Augšdaļa 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Atjaunot"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Piestiprināt pa kreisi"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Piestiprināt pa labi"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Mainīt lietotnes loga lielumu uz kreiso pusi"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Mainīt lietotnes loga lielumu uz labo pusi"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimizēt vai atjaunot loga lielumu"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Ieslēgt ekrāna sadalīšanas režīmu"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Ieslēgt darbvirsmas logu režīmu"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Mainīt loga lielumu uz kreiso pusi"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Mainīt loga lielumu uz labo pusi"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizēt vai atjaunot loga lielumu"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimizēt vai atjaunot loga lielumu"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizēt lietotnes logu"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Atvērt pēc noklusējuma iestatījumiem"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Izvēlieties, kā atvērt šajā lietotnē norādītās saites"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Lietotnē"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 6593e2d9e66b..f7177acc8681 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левиот 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левиот 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десниот на цел екран"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Менувајте апликации"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горниот на цел екран"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горниот 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горниот 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Врати"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Фотографирај лево"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Фотографирај десно"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Променете ја големината на прозорецот на апликацијата одлево"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Променете ја големината на прозорецот на апликацијата оддесно"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Максимизирајте или вратете ја големината на прозорецот"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Влезете во „Режим на поделен екран“"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Влезете во „Режим со прозорци на работната површина“"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Променете ја големината на прозорецот налево"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Променете ја големината на прозорецот надесно"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Максимизирајте или вратете ја големината на прозорецот"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Максимизирајте или вратете ја големината на прозорецот"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Минимизирајте го прозорецот на апликацијата"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Отвори според стандардните поставки"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Изберете како да се отвораат линковите за апликацијава"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Во апликацијата"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 8914e1fa782a..b38026cc5445 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Зүүн 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Зүүн 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Баруун талын бүтэн дэлгэц"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Аппуудыг солих"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Дээд талын бүтэн дэлгэц"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Дээд 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Дээд 50%"</string>
@@ -130,7 +129,7 @@
<string name="open_in_app_text" msgid="2874590745116268525">"Аппад нээх"</string>
<string name="new_window_text" msgid="6318648868380652280">"Шинэ цонх"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Windows-г удирдах"</string>
- <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Харьцааг өөрчлөх"</string>
+ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Аспектын харьцааг өөрчлөх"</string>
<string name="close_text" msgid="4986518933445178928">"Хаах"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Цэсийг нээх"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Сэргээх"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Зүүн тийш зэрэгцүүлэх"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Баруун тийш зэрэгцүүлэх"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Аппын цонхны хэмжээг зүүн тал руу өөрчлөх"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Аппын цонхны хэмжээг баруун тал руу өөрчлөх"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Дэлгэц хуваах горимд орох"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Дэлгэцийн цонхны горимд орох"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Цонхны хэмжээг зүүн тал руу өөрчлөх"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Цонхны хэмжээг баруун тал руу өөрчлөх"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Аппын цонхыг жижгэрүүлэх"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Өгөгдмөл тохиргоогоор нээх"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Энэ аппад веб холбоосыг хэрхэн нээхийг сонгоно уу"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Аппад"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 81594798ef48..d9c1d1f45a55 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"डावी 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"डावी 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"उजवी फुल स्क्रीन"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"अ‍ॅप्स स्वॅप करा"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"शीर्ष फुल स्क्रीन"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"शीर्ष 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"शीर्ष 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"रिस्टोअर करा"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"डावीकडे स्नॅप करा"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"उजवीकडे स्नॅप करा"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"अ‍ॅप विंडोचा डावीकडून आकार बदला"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"अ‍ॅप विंडोचा उजवीकडून आकार बदला"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"स्प्लिट स्क्रीन मोड एंटर करा"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"डेस्कटॉप विंडोइंग मोड एंटर करा"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"अ‍ॅप विंडोचा डावीकडे आकार बदला"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"अ‍ॅप विंडोचा उजवीकडे आकार बदला"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"अ‍ॅप विंडो लहान करा"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"बाय डीफॉल्ट सेटिंग्ज उघडा"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"या अ‍ॅपसाठीच्या वेब लिंक कशा उघडाव्यात हे निवडा"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ॲपमध्ये"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index b749b670f74d..1f4db6d9b872 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ဘယ်ဘက် မျက်နှာပြင် ၅၀%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ဘယ်ဘက် မျက်နှာပြင် ၃၀%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ညာဘက် မျက်နှာပြင်အပြည့်"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"အက်ပ်ပြောင်းရန်"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"အပေါ်ဘက် မျက်နှာပြင်အပြည့်"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"အပေါ်ဘက် မျက်နှာပြင် ၇၀%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"အပေါ်ဘက် မျက်နှာပြင် ၅၀%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ပြန်ပြောင်းရန်"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ဘယ်တွင် ချဲ့ရန်"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ညာတွင် ချဲ့ရန်"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"အက်ပ်ဝင်းဒိုး ဘယ်ဘက်ကို အရွယ်ပြင်ရန်"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"အက်ပ်ဝင်းဒိုး ညာဘက်ကို အရွယ်ပြင်ရန်"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"မျက်နှာပြင်ခွဲပြခြင်းမုဒ်သို့ ဝင်ရန်"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ဒက်စ်တော့ ဝင်းဒိုးမုဒ်သို့ ဝင်ရန်"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ဝင်းဒိုးကို ဘယ်ဘက်သို့ အရွယ်ပြင်ရန်"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ဝင်းဒိုးကို ညာဘက်သို့ အရွယ်ပြင်ရန်"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"အက်ပ်ဝင်းဒိုးကို ချုံ့ရန်"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"မူရင်းဆက်တင်ဖြင့် ဖွင့်ရန်"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ဤအက်ပ်အတွက် ဝဘ်လင့်ခ်များ မည်သို့ဖွင့်မည်ကို ရွေးပါ"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"အက်ပ်တွင်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 86aa19650003..586a50f74f0d 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sett størrelsen på den venstre delen av skjermen til 50 %"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sett størrelsen på den venstre delen av skjermen til 30 %"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Utvid den høyre delen av skjermen til hele skjermen"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Bytt apper"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Utvid den øverste delen av skjermen til hele skjermen"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Sett størrelsen på den øverste delen av skjermen til 70 %"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Sett størrelsen på den øverste delen av skjermen til 50 %"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Gjenopprett"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Fest til venstre"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Fest til høyre"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Endre størrelsen på appvinduet til venstre"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Endre størrelsen på appvinduet til høyre"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimer eller gjenopprett størrelsen på vinduet"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Start modusen for delt skjerm"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Start vindusmodus for skrivebordet"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Endre størrelsen på vinduet til venstre"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Endre størrelsen på vinduet til høyre"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimer eller gjenopprett størrelsen på vinduet"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimer eller gjenopprett størrelsen på vinduet"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimer appvinduet"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Innstillinger for åpning som standard"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Velg hvordan nettlinker skal åpnes for denne appen"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index bc45b0f45750..f66fb1d30359 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बायाँ भाग ५०%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बायाँ भाग ३०%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दायाँ भाग फुल स्क्रिन"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"एपहरू अदलबदल गर्नुहोस्"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"माथिल्लो भाग फुल स्क्रिन"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"माथिल्लो भाग ७०%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"माथिल्लो भाग ५०%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"रिस्टोर गर्नुहोस्"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"बायाँतिर स्न्याप गर्नुहोस्"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"दायाँतिर स्न्याप गर्नुहोस्"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"एपको विन्डोको आकार बदलेर बायाँतिर लैजानुहोस्"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"एपको विन्डोको आकार बदलेर दायाँतिर लैजानुहोस्"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"स्प्लिट स्क्रिन मोड प्रयोग गर्नुहोस्"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"डेस्कटप विन्डोइङ मोड प्रयोग गर्नुहोस्"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विन्डोको आकार बदलेर बायाँतिर लैजानुहोस्"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विन्डोको आकार बदलेर दायाँतिर लैजानुहोस्"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"एपको विन्डो मिनिमाइज गर्नुहोस्"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफल्ट सेटिङअनुसार खोल्नुहोस्"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"यो एपका वेब लिंकहरू खोल्ने तरिका छनौट गर्नुहोस्"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"एपमा"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index b16092ec46f9..edb520872d1f 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ବାମ ପଟକୁ 50% କରନ୍ତୁ"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ବାମ ପଟେ 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ଡାହାଣ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍ କରନ୍ତୁ"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ଆପ୍ସ ସ୍ୱାପ କରନ୍ତୁ"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ଉପର ଆଡ଼କୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍ କରନ୍ତୁ"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ଉପର ଆଡ଼କୁ 70% କରନ୍ତୁ"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ଉପର ଆଡ଼କୁ 50% କରନ୍ତୁ"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ବାମରେ ସ୍ନାପ କରନ୍ତୁ"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ଡାହାଣରେ ସ୍ନାପ କରନ୍ତୁ"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ଆପ ୱିଣ୍ଡୋ ରିସାଇଜ କରିବା ପାଇଁ ବାମ ବଟନ"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ଆପ ୱିଣ୍ଡୋ ରିସାଇଜ କରିବା ପାଇଁ ଡାହାଣ ବଟନ"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ୱିଣ୍ଡୋ ସାଇଜକୁ ମେକ୍ସିମାଇଜ କିମ୍ବା ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ମୋଡରେ ପ୍ରବେଶ କରନ୍ତୁ"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ଡେସ୍କଟପ ୱିଣ୍ଡୋଇଂ ମୋଡରେ ପ୍ରବେଶ କରନ୍ତୁ"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ବାମପଟକୁ ୱିଣ୍ଡୋ ରିସାଇଜ କରନ୍ତୁ"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ଡାହାଣପଟକୁ ୱିଣ୍ଡୋ ରିସାଇଜ କରନ୍ତୁ"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ୱିଣ୍ଡୋ ସାଇଜକୁ ମେକ୍ସିମାଇଜ କିମ୍ବା ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ୱିଣ୍ଡୋ ସାଇଜକୁ ମେକ୍ସିମାଇଜ କିମ୍ବା ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ଆପ ୱିଣ୍ଡୋକୁ ମିନିମାଇଜ କରନ୍ତୁ"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"ଡିଫଲ୍ଟ ସେଟିଂସକୁ ଖୋଲନ୍ତୁ"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ଏହି ଆପ ପାଇଁ ୱେବ ଲିଙ୍କଗୁଡ଼ିକୁ କିପରି ଖୋଲିବେ, ତାହା ବାଛନ୍ତୁ"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ଆପରେ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index d06603fbe206..47ee80e6a4e8 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% lewej części ekranu"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% lewej części ekranu"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Prawa część ekranu na pełnym ekranie"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Zamień aplikacje"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Górna część ekranu na pełnym ekranie"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% górnej części ekranu"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% górnej części ekranu"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Przywróć"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Przyciągnij do lewej"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Przyciągnij do prawej"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Zmień rozmiar okna aplikacji po lewej"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Zmień rozmiar okna aplikacji po prawej"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Zmaksymalizuj lub przywróć rozmiar okna"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Włącz tryb podzielonego ekranu"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Włącz tryb okien na pulpicie"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Zmień rozmiar okna do lewej"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Zmień rozmiar okna do prawej"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Zmaksymalizuj lub przywróć rozmiar okna"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Zmaksymalizuj lub przywróć rozmiar okna"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Zminimalizuj okno aplikacji"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Ustawienia domyślnego otwierania"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Wybierz, gdzie chcesz otwierać linki z tej aplikacji"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"W aplikacji"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 3039950e47ee..a3313b6496e0 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Partea stângă: 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Partea stângă: 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Partea dreaptă pe ecran complet"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Comută între aplicații"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Partea de sus pe ecran complet"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Partea de sus: 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Partea de sus: 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restabilește"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Trage la stânga"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Trage la dreapta"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionează fereastra aplicației la stânga"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionează fereastra aplicației la dreapta"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizează sau restabilește dimensiunea ferestrei"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Accesează modul ecran împărțit"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Accesează modul de windowing pe desktop"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionează fereastra la stânga"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionează fereastra la dreapta"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizează sau restabilește dimensiunea ferestrei"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximizează sau restabilește dimensiunea ferestrei"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizează fereastra aplicației"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Setări de deschidere în mod prestabilit"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Alege modul de deschidere a linkurilor web pentru aplicație"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"În aplicație"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index fe03feb901ed..fcb0aa6559fa 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Majtas 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Majtas 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ekrani i plotë djathtas"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Ndërro aplikacionet"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ekrani i plotë lart"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Lart 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Lart 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restauro"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Zhvendos majtas"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Zhvendos djathtas"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ndrysho përmasat e dritares së aplikacionit majtas"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ndrysho përmasat e dritares së aplikacionit djathtas"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimizo ose restauro madhësinë e dritares"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Hyr në modalitetin e ekranit të ndarë"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Hyr në modalitetin e dritareve në desktop"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ndrysho përmasat e dritares në të majtë"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ndrysho përmasat e dritares në të djathtë"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizo ose restauro madhësinë e dritares"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimizo ose restauro madhësinë e dritares"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizo dritaren e aplikacionit"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Hap sipas cilësimeve të parazgjedhura"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Zgjidh si do t\'i hapësh lidhjet e uebit për këtë aplikacion"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Në aplikacion"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 5163fc69dfb5..6a2ffcdf8e89 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -125,11 +125,11 @@
<string name="float_button_text" msgid="9221657008391364581">"Плутајуће"</string>
<string name="select_text" msgid="5139083974039906583">"Изаберите"</string>
<string name="screenshot_text" msgid="1477704010087786671">"Снимак екрана"</string>
- <string name="open_in_browser_text" msgid="9181692926376072904">"Отворите у прегледачу"</string>
+ <string name="open_in_browser_text" msgid="9181692926376072904">"Отвори у прегледачу"</string>
<string name="open_in_app_text" msgid="2874590745116268525">"Отворите у апликацији"</string>
<string name="new_window_text" msgid="6318648868380652280">"Нови прозор"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"Управљајте прозорима"</string>
- <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промените размеру"</string>
+ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени размеру"</string>
<string name="close_text" msgid="4986518933445178928">"Затворите"</string>
<string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string>
<string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отворите мени"</string>
@@ -138,7 +138,7 @@
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликација не може да се премести овде"</string>
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Имерзивне"</string>
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Врати"</string>
- <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Увећајте"</string>
+ <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Увећај"</string>
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Вратите"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Прикачите лево"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Прикачите десно"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 29f4aab0502a..a9df47650dad 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vänster 50 %"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vänster 30 %"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Helskärm på höger skärm"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Byt appar"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Helskärm på övre skärm"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Övre 70 %"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Övre 50 %"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Återställ"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Fäst till vänster"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Fäst till höger"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ändra storlek på appfönstret åt vänster"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ändra storlek på appfönstret åt höger"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximera eller återställ fönsterstorleken"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Starta läget för delad skärm"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Starta datorläget"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ändra storlek på fönstret åt vänster"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ändra storlek på fönstret åt höger"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximera eller återställ fönsterstorleken"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximera eller återställ fönsterstorleken"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimera appfönstret"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Inställningar för Öppna som standard"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Välj hur webblänkar ska öppnas för den här appen"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 6471e3b723e0..a3c9a0d3989c 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kushoto 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kushoto 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Skrini nzima ya kulia"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Badilisha Programu"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Skrini nzima ya juu"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Juu 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Juu 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Rejesha"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Telezesha kushoto"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Telezesha kulia"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Badilisha ukubwa wa dirisha la programu kushoto"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Badilisha ukubwa wa dirisha la programu kulia"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Panua au urejeshe ukubwa wa dirisha"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Ingia katika hali ya skrini iliyogawanywa"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Ingia katika hali ya madirisha ya kompyuta ya mezani"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Badilisha ukubwa wa dirisha kushoto"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Badilisha ukubwa wa dirisha kulia"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Panua au urejeshe ukubwa wa dirisha"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Panua au urejeshe ukubwa wa dirisha"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Punguza dirisha la programu"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Fungua kwa mipangilio chaguomsingi"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chagua jinsi ya kufungua viungo vya wavuti vya programu hii"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Kwenye programu"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 03e55c8dcf79..b1b8c7ff2075 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"இடது புறம் 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"இடது புறம் 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"வலது புறம் முழுத் திரை"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ஆப்ஸை மாற்றும்"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"மேற்புறம் முழுத் திரை"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"மேலே 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"மேலே 50%"</string>
@@ -126,7 +125,7 @@
<string name="float_button_text" msgid="9221657008391364581">"மிதக்கும் சாளரம்"</string>
<string name="select_text" msgid="5139083974039906583">"தேர்ந்தெடுக்கும்"</string>
<string name="screenshot_text" msgid="1477704010087786671">"ஸ்கிரீன்ஷாட்"</string>
- <string name="open_in_browser_text" msgid="9181692926376072904">"உலாவியில் திறக்கும்"</string>
+ <string name="open_in_browser_text" msgid="9181692926376072904">"பிரவுசரில் திற"</string>
<string name="open_in_app_text" msgid="2874590745116268525">"ஆப்ஸில் திறக்கும்"</string>
<string name="new_window_text" msgid="6318648868380652280">"புதிய சாளரம்"</string>
<string name="manage_windows_text" msgid="5567366688493093920">"சாளரங்களை நிர்வகிக்கலாம்"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"மீட்டெடுக்கும்"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"இடதுபுறம் நகர்த்தும்"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"வலதுபுறம் நகர்த்தும்"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ஆப்ஸ் சாளரத்தின் இடதுபுறத்தில் அளவை மாற்றும்"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ஆப்ஸ் சாளரத்தின் வலதுபுறத்தில் அளவை மாற்றும்"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"திரைப் பிரிப்புப் பயன்முறையில் உள்நுழையும்"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"டெஸ்க்டாப் சாளரப் பயன்முறையில் உள்நுழையும்"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"சாளரத்தை இடதுபுறமாக அளவு மாற்றும்"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"சாளரத்தை வலதுபுறமாக அளவு மாற்றும்"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ஆப்ஸ் சாளரத்தைச் சிறிதாக்கும்"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"இயல்பாக அமைப்புகளைத் திறக்கும்"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"இந்த ஆப்ஸில் வலை இணைப்புகளைத் திறக்கும் வழிமுறையைத் தேர்வுசெய்யுங்கள்"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ஆப்ஸில்"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 8d12e5437c62..6a5d1abebd25 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Solda %50"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Solda %30"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağda tam ekran"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Uygulamaların Yerini Değiştir"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Üstte tam ekran"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Üstte %70"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Üstte %50"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Geri yükle"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Sola tuttur"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Sağa tuttur"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Uygulama penceresini sola yeniden boyutlandır"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Uygulama penceresini sağa yeniden boyutlandır"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Bölünmüş ekran moduna gir"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masaüstü pencereleme moduna gir"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pencereyi sola yeniden boyutlandır"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pencereyi sağa yeniden boyutlandır"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Uygulama penceresini küçült"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Varsayılan olarak açma ayarları"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu uygulama için web bağlantılarının nasıl açılacağını seçin"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Uygulamada"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 66d8a62f6633..7f4e91d5dfc5 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ліве вікно на 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ліве вікно на 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Праве вікно на весь екран"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Поміняти додатки місцями"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхнє вікно на весь екран"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхнє вікно на 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхнє вікно на 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Відновити"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Закріпити ліворуч"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Закріпити праворуч"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Змінити розмір вікна додатка ліворуч"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Змінити розмір вікна додатка праворуч"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Розгорнути вікно або відновити його розмір"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Увімкнути режим розділення екрана"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Увімкнути режим вікон для комп’ютера"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Змінити розмір вікна ліворуч"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Змінити розмір вікна праворуч"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Розгорнути вікно або відновити його розмір"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Розгорнути вікно або відновити його розмір"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Згорнути вікно додатка"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Налаштування \"Відкривати за умовчанням\""</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Виберіть, як відкривати вебпосилання в цьому додатку"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"У додатку"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 653ba0e66984..f461d4077087 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"بائیں %50"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"بائیں %30"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"دائیں فل اسکرین"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ایپس سویپ کریں"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"بالائی فل اسکرین"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"اوپر %70"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"اوپر %50"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"بحال کریں"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"دائیں منتقل کریں"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"بائیں منتقل کریں"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"دائیں طرف ایپ ونڈو کا سائز تبدیل کریں"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ایپ ونڈو کا سائز بائیں طرف تبدیل کریں"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"سپلٹ اسکرین موڈ میں داخل ہوں"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ڈیسک ٹاپ ونڈو وضع میں داخل ہوں"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"دائیں طرف ونڈو کا سائز تبدیل کریں"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ونڈو کا سائز بائیں طرف تبدیل کریں"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ایپ ونڈو کو چھوٹا کریں"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"بطور ڈیفالٹ ترتیبات کھولیں"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اس ایپ کے لیے ویب لنکس کھولنے کا طریقہ منتخب کریں"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ایپ میں"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index f1b728b1b64c..e7cacc345c2b 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Trái 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Trái 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Toàn màn hình bên phải"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Hoán đổi ứng dụng"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Toàn màn hình phía trên"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Trên 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Trên 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Khôi phục"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Di chuyển nhanh sang trái"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Di chuyển nhanh sang phải"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Đổi kích thước và chuyển cửa sổ ứng dụng sang trái"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Đổi kích thước và chuyển cửa sổ ứng dụng sang phải"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Phóng to hoặc khôi phục kích thước cửa sổ"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Mở chế độ chia đôi màn hình"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Mở chế độ cửa sổ trên máy tính"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Đổi kích thước và chuyển cửa sổ sang trái"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Đổi kích thước và chuyển cửa sổ sang phải"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Phóng to hoặc khôi phục kích thước cửa sổ"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Phóng to hoặc khôi phục kích thước cửa sổ"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Thu nhỏ cửa sổ ứng dụng"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Mở các chế độ cài đặt theo mặc định"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chọn cách mở đường liên kết trang web cho ứng dụng này"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Trong ứng dụng"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 543780844060..562a0ee09bd6 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左侧 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左侧 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右侧全屏"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"交换应用位置"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"顶部全屏"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"顶部 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"顶部 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"恢复"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"贴靠左侧"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"贴靠右侧"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"调整应用窗口大小并贴靠左侧"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"调整应用窗口大小并贴靠右侧"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"将窗口最大化或恢复大小"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"进入分屏模式"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"进入桌面设备窗口化模式"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"调整窗口大小并贴靠左侧"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"调整窗口大小并贴靠右侧"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"将窗口最大化或恢复大小"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"将窗口最大化或恢复大小"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"将应用窗口最小化"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"默认打开设置"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"选择如何打开此应用中的网页链接"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在此应用内"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 938024d2cd1a..eecd9f21be57 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左邊 50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左邊 30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右邊全螢幕"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"切換應用程式"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"頂部全螢幕"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"頂部 70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"頂部 50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"還原"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"貼齊左邊"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"貼齊右邊"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"調整左邊應用程式視窗大小"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"調整右邊應用程式視窗大小"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"將視窗放到最大或者還原視窗大小"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"進入分割螢幕模式"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"進入桌面視窗模式"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"將視窗移去左邊調整大小"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"將視窗移去右邊調整大小"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗放到最大或者還原視窗大小"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"將視窗放到最大或者還原視窗大小"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"將應用程式視窗縮到最細"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"採用預設設定打開"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇此應用程式開啟網絡連結的方式"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在應用程式內"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 3a5a87d9868e..c157c193fa14 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"以 50% 的螢幕空間顯示左側畫面"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"以 30% 的螢幕空間顯示左側畫面"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"以全螢幕顯示右側畫面"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"切換應用程式"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"以全螢幕顯示頂端畫面"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"以 70% 的螢幕空間顯示頂端畫面"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"以 50% 的螢幕空間顯示頂端畫面"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"還原"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"靠左對齊"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"靠右對齊"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"調整應用程式視窗大小並向左貼齊"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"調整應用程式視窗大小並向右貼齊"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"將視窗最大化或還原大小"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"進入分割畫面模式"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"進入電腦視窗化模式"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"調整應用程式視窗大小並向左貼齊"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"調整應用程式視窗大小並向右貼齊"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗最大化或還原大小"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"將視窗最大化或還原大小"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"將應用程式視窗最小化"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"開啟連結的預設設定"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇如何開啟這個應用程式的網頁連結"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"使用應用程式"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index cba8e048ea3d..a7ba6d21234d 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -43,8 +43,7 @@
<string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kwesokunxele ngo-50%"</string>
<string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kwesokunxele ngo-30%"</string>
<string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Isikrini esigcwele esingakwesokudla"</string>
- <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) -->
- <skip />
+ <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Shintsha ama-app"</string>
<string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Isikrini esigcwele esiphezulu"</string>
<string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Okuphezulu okungu-70%"</string>
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Okuphezulu okungu-50%"</string>
@@ -143,26 +142,16 @@
<string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Buyisela"</string>
<string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Chofoza kwesobunxele"</string>
<string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Chofoza kwesokudla"</string>
- <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) -->
- <skip />
- <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) -->
- <skip />
- <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) -->
- <skip />
- <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) -->
- <skip />
- <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) -->
- <skip />
- <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) -->
- <skip />
+ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Shintsha usayizi we-app yewindi ngakwesokunxele"</string>
+ <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Shintsha usayizi we-app yewindi ngakwesokudla"</string>
+ <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Khulisa noma buyisela usayizi wewindi"</string>
+ <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Faka imodi yokuhlukanisa isikrini"</string>
+ <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Faka imodi yokwenza iwindi yedeskithophu"</string>
+ <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Shintsha usayizi wewindi ngakwesokunxele"</string>
+ <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Shintsha usayizi wewindi ngakwesokudla"</string>
+ <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Khulisa noma buyisela usayizi wewindi"</string>
+ <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Khulisa noma buyisela usayizi wewindi"</string>
+ <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Nciphisa iwindi le-app"</string>
<string name="open_by_default_settings_text" msgid="2526548548598185500">"Vula amasethingi ngokuzenzakalela"</string>
<string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Khetha indlela yokuvula amalinki ewebhu ale app"</string>
<string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Ku-app"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 96e008e42f1c..f5f3f0fe52eb 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -447,6 +447,17 @@
80 dp for handle + 20 dp for room to grow on the sides when hovered. -->
<dimen name="desktop_mode_fullscreen_decor_caption_width">100dp</dimen>
+ <!-- Horizontal padding for desktop mode caption in default unhovered untouched state. -->
+ <dimen name="desktop_mode_fullscreen_decor_caption_horizontal_padding_default">10dp</dimen>
+
+ <!-- Horizontal padding for desktop mode caption when hovered.
+ 1/2 * (100 dp of total width - 80 dp for handle * 1.2 scaling factor). -->
+ <dimen name="desktop_mode_fullscreen_decor_caption_horizontal_padding_hovered">2dp</dimen>
+
+ <!-- Horizontal padding for desktop mode caption when touched.
+ 1/2 * (100 dp of total width - 80 dp for handle * 0.85 scaling factor). -->
+ <dimen name="desktop_mode_fullscreen_decor_caption_horizontal_padding_touched">16dp</dimen>
+
<!-- Required empty space to be visible for partially offscreen tasks. -->
<dimen name="freeform_required_visible_empty_space_in_header">48dp</dimen>
@@ -487,14 +498,6 @@
<!-- The default minimum allowed window height when resizing a window in desktop mode. -->
<dimen name="desktop_mode_minimum_window_height">352dp</dimen>
- <!-- The width of the maximize menu in desktop mode, depending on the number of options -->
- <dimen name="desktop_mode_maximize_menu_width_one_options">126dp</dimen>
- <dimen name="desktop_mode_maximize_menu_width_two_options">228dp</dimen>
- <dimen name="desktop_mode_maximize_menu_width_three_options">330dp</dimen>
-
- <!-- The height of the maximize menu in desktop mode. -->
- <dimen name="desktop_mode_maximize_menu_height">114dp</dimen>
-
<!-- The padding of the maximize menu in desktop mode. -->
<dimen name="desktop_mode_menu_padding">16dp</dimen>
diff --git a/libs/WindowManager/Shell/shared/res/color/bubble_drop_target_background_color.xml b/libs/WindowManager/Shell/shared/res/color/bubble_drop_target_background_color.xml
new file mode 100644
index 000000000000..975d25b25953
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/res/color/bubble_drop_target_background_color.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2025 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"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:alpha="0.35" android:color="@androidprv:color/materialColorPrimaryContainer" />
+</selector>
diff --git a/libs/WindowManager/Shell/shared/res/drawable/bubble_drop_target_background.xml b/libs/WindowManager/Shell/shared/res/drawable/bubble_drop_target_background.xml
new file mode 100644
index 000000000000..89546f9b0807
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/res/drawable/bubble_drop_target_background.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <corners android:radius="28dp" />
+ <solid android:color="@color/bubble_drop_target_background_color" />
+ <stroke
+ android:width="1dp"
+ android:color="@androidprv:color/materialColorPrimaryContainer" />
+</shape>
diff --git a/libs/WindowManager/Shell/shared/res/values/dimen.xml b/libs/WindowManager/Shell/shared/res/values/dimen.xml
index d280083ae7f5..11a6f32d7454 100644
--- a/libs/WindowManager/Shell/shared/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/shared/res/values/dimen.xml
@@ -36,4 +36,14 @@
<dimen name="drag_zone_v_split_from_expanded_view_height_tablet">285dp</dimen>
<dimen name="drag_zone_v_split_from_expanded_view_height_fold_tall">150dp</dimen>
<dimen name="drag_zone_v_split_from_expanded_view_height_fold_short">100dp</dimen>
+
+ <!-- Bubble drop target dimensions -->
+ <dimen name="drop_target_elevation">1dp</dimen>
+ <dimen name="drop_target_full_screen_padding">20dp</dimen>
+ <dimen name="drop_target_desktop_window_padding_small">100dp</dimen>
+ <dimen name="drop_target_desktop_window_padding_large">130dp</dimen>
+ <dimen name="drop_target_expanded_view_width">364</dimen>
+ <dimen name="drop_target_expanded_view_height">578</dimen>
+ <dimen name="drop_target_expanded_view_padding_bottom">108</dimen>
+ <dimen name="drop_target_expanded_view_padding_horizontal">24</dimen>
</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
index 4d00c74155a8..851987269c10 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
@@ -21,6 +21,7 @@ import static android.view.RemoteAnimationTarget.MODE_CHANGING;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
+import static android.view.WindowManager.LayoutParams.LAST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -55,9 +56,15 @@ import java.util.function.Predicate;
public class TransitionUtil {
/** Flag applied to a transition change to identify it as a divider bar for animation. */
public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
+ public static final int FLAG_IS_DIM_LAYER = FLAG_FIRST_CUSTOM << 1;
/** Flag applied to a transition change to identify it as a desktop wallpaper activity. */
- public static final int FLAG_IS_DESKTOP_WALLPAPER_ACTIVITY = FLAG_FIRST_CUSTOM << 1;
+ public static final int FLAG_IS_DESKTOP_WALLPAPER_ACTIVITY = FLAG_FIRST_CUSTOM << 2;
+
+ /**
+ * Applied to a {@link RemoteAnimationTarget} to identify dim layers for animation in Launcher.
+ */
+ public static final int TYPE_SPLIT_SCREEN_DIM_LAYER = LAST_SYSTEM_WINDOW + 1;
/** @return true if the transition was triggered by opening something vs closing something */
public static boolean isOpeningType(@WindowManager.TransitionType int type) {
@@ -117,6 +124,11 @@ public class TransitionUtil {
return isNonApp(change) && change.hasFlags(FLAG_IS_DIVIDER_BAR);
}
+ /** Returns `true` if `change` is an app's dim layer. */
+ public static boolean isDimLayer(TransitionInfo.Change change) {
+ return isNonApp(change) && change.hasFlags(FLAG_IS_DIM_LAYER);
+ }
+
/** Returns `true` if `change` is only re-ordering. */
public static boolean isOrderOnly(TransitionInfo.Change change) {
return change.getMode() == TRANSIT_CHANGE
@@ -231,6 +243,14 @@ public class TransitionUtil {
t.setLayer(leash, Integer.MAX_VALUE);
return;
}
+ if (isDimLayer(change)) {
+ // When a dim layer gets reparented onto the transition root, we need to zero out its
+ // position so that it's in line with everything else on the transition root. Also,
+ // we need to set a crop because we don't want it applying MATCH_PARENT on the whole
+ // root surface.
+ t.setPosition(leash, 0, 0);
+ t.setCrop(leash, change.getEndAbsBounds());
+ }
// Put all the OPEN/SHOW on top
if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
@@ -284,14 +304,19 @@ public class TransitionUtil {
// Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
setupLeash(leashSurface, change, info.getChanges().size() - order, info, t);
t.reparent(change.getLeash(), leashSurface);
- t.setAlpha(change.getLeash(), 1.0f);
- t.show(change.getLeash());
+ if (!isDimLayer(change)) {
+ // Most leashes going onto the transition root should have their alpha set here to make
+ // them visible. But dim layers should be left untouched (their alpha value is their
+ // actual dim value).
+ t.setAlpha(change.getLeash(), 1.0f);
+ }
if (!isDividerBar(change)) {
// For divider, don't modify its inner leash position when creating the outer leash
// for the transition. In case the position being wrong after the transition finished.
t.setPosition(change.getLeash(), 0, 0);
}
t.setLayer(change.getLeash(), 0);
+ t.show(change.getLeash());
return leashSurface;
}
@@ -333,6 +358,9 @@ public class TransitionUtil {
if (isDividerBar(change)) {
return getDividerTarget(change, leash);
}
+ if (isDimLayer(change)) {
+ return getDimLayerTarget(change, leash);
+ }
int taskId;
boolean isNotInRecents;
@@ -439,6 +467,17 @@ public class TransitionUtil {
TYPE_DOCK_DIVIDER);
}
+ private static RemoteAnimationTarget getDimLayerTarget(TransitionInfo.Change change,
+ SurfaceControl leash) {
+ return new RemoteAnimationTarget(-1 /* taskId */, newModeToLegacyMode(change.getMode()),
+ leash, false /* isTranslucent */, null /* clipRect */,
+ null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */,
+ new android.graphics.Point(0, 0) /* position */, change.getStartAbsBounds(),
+ change.getStartAbsBounds(), new WindowConfiguration(), true, null /* startLeash */,
+ null /* startBounds */, null /* taskInfo */, false /* allowEnterPip */,
+ TYPE_SPLIT_SCREEN_DIM_LAYER);
+ }
+
/**
* Finds the "correct" root idx for a change. The change's end display is prioritized, then
* the start display. If there is no display, it will fallback on the 0th root in the
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java
index f45dc3a1e892..e92c1eb81e89 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/Interpolators.java
@@ -93,10 +93,21 @@ public class Interpolators {
public static final PathInterpolator SLOWDOWN_INTERPOLATOR =
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
+ /**
+ * An interpolator used for dimming a task as it travels offscreen, or towards a distant dismiss
+ * point. A sharp rise, followed by a steady middle, and ending with another sharp rise.
+ */
public static final PathInterpolator DIM_INTERPOLATOR =
new PathInterpolator(.23f, .87f, .52f, -0.11f);
/**
+ * An interpolator used for dimming a task very quickly. Roughly approximates one of the "sharp
+ * rises" of {@link #DIM_INTERPOLATOR}.
+ */
+ public static final PathInterpolator FAST_DIM_INTERPOLATOR =
+ new PathInterpolator(0.23f, 0.87f, 0.83f, 0.83f);
+
+ /**
* Use this interpolator for animating progress values coming from the back callback to get
* the predictive-back-typical decelerate motion.
*
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleBarLocation.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleBarLocation.kt
index 481fc7fcb869..6acd9dbe8b91 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleBarLocation.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleBarLocation.kt
@@ -70,7 +70,8 @@ enum class BubbleBarLocation : Parcelable {
UpdateSource.A11Y_ACTION_BAR,
UpdateSource.A11Y_ACTION_BUBBLE,
UpdateSource.A11Y_ACTION_EXP_VIEW,
- UpdateSource.APP_ICON_DRAG
+ UpdateSource.APP_ICON_DRAG,
+ UpdateSource.DRAG_TASK,
)
@Retention(AnnotationRetention.SOURCE)
annotation class UpdateSource {
@@ -95,6 +96,9 @@ enum class BubbleBarLocation : Parcelable {
/** Location changed from dragging the application icon to the bubble bar */
const val APP_ICON_DRAG = 7
+
+ /** Location changed from dragging a running task to the bubble bar */
+ const val DRAG_TASK = 8
}
}
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt
index 5d346c047123..6eff75c9a479 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt
@@ -31,29 +31,41 @@ sealed interface DragZone {
/** The bounds of this drag zone. */
val bounds: Rect
+ /** The bounds of the drop target associated with this drag zone. */
+ val dropTarget: Rect?
fun contains(x: Int, y: Int) = bounds.contains(x, y)
/** Represents the bubble drag area on the screen. */
- sealed class Bubble(override val bounds: Rect) : DragZone {
- data class Left(override val bounds: Rect, val dropTarget: Rect) : Bubble(bounds)
- data class Right(override val bounds: Rect, val dropTarget: Rect) : Bubble(bounds)
+ sealed class Bubble(override val bounds: Rect, override val dropTarget: Rect) : DragZone {
+ data class Left(override val bounds: Rect, override val dropTarget: Rect) :
+ Bubble(bounds, dropTarget)
+
+ data class Right(override val bounds: Rect, override val dropTarget: Rect) :
+ Bubble(bounds, dropTarget)
}
/** Represents dragging to Desktop Window. */
- data class DesktopWindow(override val bounds: Rect, val dropTarget: Rect) : DragZone
+ data class DesktopWindow(override val bounds: Rect, override val dropTarget: Rect) : DragZone
/** Represents dragging to Full Screen. */
- data class FullScreen(override val bounds: Rect, val dropTarget: Rect) : DragZone
+ data class FullScreen(override val bounds: Rect, override val dropTarget: Rect) : DragZone
/** Represents dragging to dismiss. */
- data class Dismiss(override val bounds: Rect) : DragZone
+ data class Dismiss(override val bounds: Rect) : DragZone {
+ override val dropTarget: Rect? = null
+ }
/** Represents dragging to enter Split or replace a Split app. */
sealed class Split(override val bounds: Rect) : DragZone {
+ override val dropTarget: Rect? = null
+
data class Left(override val bounds: Rect) : Split(bounds)
+
data class Right(override val bounds: Rect) : Split(bounds)
+
data class Top(override val bounds: Rect) : Split(bounds)
+
data class Bottom(override val bounds: Rect) : Split(bounds)
}
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt
index 909e9d2c4428..1a80b0f29aa9 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.shared.bubbles
import android.content.Context
import android.graphics.Rect
+import android.util.TypedValue
import androidx.annotation.DimenRes
import com.android.wm.shell.shared.R
import com.android.wm.shell.shared.bubbles.DragZoneFactory.SplitScreenModeChecker.SplitScreenMode
@@ -50,6 +51,60 @@ class DragZoneFactory(
private var vSplitFromExpandedViewDragZoneHeightFoldTall = 0
private var vSplitFromExpandedViewDragZoneHeightFoldShort = 0
+ private var fullScreenDropTargetPadding = 0
+ private var desktopWindowDropTargetPaddingSmall = 0
+ private var desktopWindowDropTargetPaddingLarge = 0
+ private var expandedViewDropTargetWidth = 0
+ private var expandedViewDropTargetHeight = 0
+ private var expandedViewDropTargetPaddingBottom = 0
+ private var expandedViewDropTargetPaddingHorizontal = 0
+
+ private val fullScreenDropTarget: Rect
+ get() =
+ Rect(windowBounds).apply {
+ inset(fullScreenDropTargetPadding, fullScreenDropTargetPadding)
+ }
+
+ private val desktopWindowDropTarget: Rect
+ get() =
+ Rect(windowBounds).apply {
+ if (deviceConfig.isLandscape) {
+ inset(
+ /* dx= */ desktopWindowDropTargetPaddingLarge,
+ /* dy= */ desktopWindowDropTargetPaddingSmall
+ )
+ } else {
+ inset(
+ /* dx= */ desktopWindowDropTargetPaddingSmall,
+ /* dy= */ desktopWindowDropTargetPaddingLarge
+ )
+ }
+ }
+
+ private val expandedViewDropTargetLeft: Rect
+ get() =
+ Rect(
+ expandedViewDropTargetPaddingHorizontal,
+ windowBounds.bottom -
+ expandedViewDropTargetPaddingBottom -
+ expandedViewDropTargetHeight,
+ expandedViewDropTargetWidth + expandedViewDropTargetPaddingHorizontal,
+ windowBounds.bottom - expandedViewDropTargetPaddingBottom
+ )
+
+ private val expandedViewDropTargetRight: Rect
+ get() =
+ Rect(
+ windowBounds.right -
+ expandedViewDropTargetPaddingHorizontal -
+ expandedViewDropTargetWidth,
+ windowBounds.bottom -
+ expandedViewDropTargetPaddingBottom -
+ expandedViewDropTargetHeight,
+ windowBounds.right - expandedViewDropTargetPaddingHorizontal,
+ windowBounds.bottom - expandedViewDropTargetPaddingBottom
+ )
+
init {
onConfigurationUpdated()
}
@@ -88,11 +143,32 @@ class DragZoneFactory(
context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_fold_tall)
vSplitFromExpandedViewDragZoneHeightFoldShort =
context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_fold_short)
+ fullScreenDropTargetPadding =
+ context.resolveDimension(R.dimen.drop_target_full_screen_padding)
+ desktopWindowDropTargetPaddingSmall =
+ context.resolveDimension(R.dimen.drop_target_desktop_window_padding_small)
+ desktopWindowDropTargetPaddingLarge =
+ context.resolveDimension(R.dimen.drop_target_desktop_window_padding_large)
+
+ // TODO b/393172431: Use the shared xml resources once we can easily access them from
+ // launcher
+ expandedViewDropTargetWidth = 364.dpToPx()
+ expandedViewDropTargetHeight = 578.dpToPx()
+ expandedViewDropTargetPaddingBottom = 108.dpToPx()
+ expandedViewDropTargetPaddingHorizontal = 24.dpToPx()
}
private fun Context.resolveDimension(@DimenRes dimension: Int) =
resources.getDimensionPixelSize(dimension)
+ private fun Int.dpToPx() =
+ TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ this.toFloat(),
+ context.resources.displayMetrics
+ )
+ .toInt()
+
/**
* Creates the list of drag zones for the dragged object.
*
@@ -155,7 +231,7 @@ class DragZoneFactory(
DragZone.Bubble.Left(
bounds =
Rect(0, windowBounds.bottom - dragZoneSize, dragZoneSize, windowBounds.bottom),
- dropTarget = Rect(0, 0, 0, 0),
+ dropTarget = expandedViewDropTargetLeft,
),
DragZone.Bubble.Right(
bounds =
@@ -165,7 +241,7 @@ class DragZoneFactory(
windowBounds.right,
windowBounds.bottom,
),
- dropTarget = Rect(0, 0, 0, 0),
+ dropTarget = expandedViewDropTargetRight,
)
)
}
@@ -174,7 +250,7 @@ class DragZoneFactory(
return listOf(
DragZone.Bubble.Left(
bounds = Rect(0, 0, windowBounds.right / 2, windowBounds.bottom),
- dropTarget = Rect(0, 0, 0, 0),
+ dropTarget = expandedViewDropTargetLeft,
),
DragZone.Bubble.Right(
bounds =
@@ -184,7 +260,7 @@ class DragZoneFactory(
windowBounds.right,
windowBounds.bottom,
),
- dropTarget = Rect(0, 0, 0, 0),
+ dropTarget = expandedViewDropTargetRight,
)
)
}
@@ -198,7 +274,7 @@ class DragZoneFactory(
windowBounds.right / 2 + fullScreenDragZoneWidth / 2,
fullScreenDragZoneHeight
),
- dropTarget = Rect(0, 0, 0, 0)
+ dropTarget = fullScreenDropTarget
)
}
@@ -223,7 +299,7 @@ class DragZoneFactory(
windowBounds.bottom / 2 + desktopWindowDragZoneHeight / 2
)
},
- dropTarget = Rect(0, 0, 0, 0)
+ dropTarget = desktopWindowDropTarget
)
}
@@ -236,7 +312,7 @@ class DragZoneFactory(
windowBounds.right / 2 + desktopWindowFromExpandedViewDragZoneWidth / 2,
windowBounds.bottom / 2 + desktopWindowFromExpandedViewDragZoneHeight / 2
),
- dropTarget = Rect(0, 0, 0, 0)
+ dropTarget = desktopWindowDropTarget
)
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt
index 29ce8d90e66f..2dc183f3f707 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt
@@ -16,22 +16,54 @@
package com.android.wm.shell.shared.bubbles
+import android.content.Context
+import android.graphics.Rect
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.animation.Animator
+import androidx.core.animation.AnimatorListenerAdapter
+import androidx.core.animation.ValueAnimator
+
/**
* Manages animating drop targets in response to dragging bubble icons or bubble expanded views
* across different drag zones.
*/
class DropTargetManager(
+ context: Context,
+ private val container: FrameLayout,
private val isLayoutRtl: Boolean,
- private val dragZoneChangedListener: DragZoneChangedListener
+ private val dragZoneChangedListener: DragZoneChangedListener,
) {
private var state: DragState? = null
+ private val dropTargetView = View(context)
+ private var animator: ValueAnimator? = null
+
+ private companion object {
+ const val ANIMATION_DURATION_MS = 250L
+ }
/** Must be called when a drag gesture is starting. */
fun onDragStarted(draggedObject: DraggedObject, dragZones: List<DragZone>) {
val state = DragState(dragZones, draggedObject)
dragZoneChangedListener.onInitialDragZoneSet(state.initialDragZone)
this.state = state
+ animator?.cancel()
+ setupDropTarget()
+ }
+
+ private fun setupDropTarget() {
+ if (dropTargetView.parent != null) container.removeView(dropTargetView)
+ container.addView(dropTargetView, 0)
+ // TODO b/393173014: set elevation and background
+ dropTargetView.alpha = 0f
+ dropTargetView.scaleX = 1f
+ dropTargetView.scaleY = 1f
+ dropTargetView.translationX = 0f
+ dropTargetView.translationY = 0f
+ // the drop target is added with a width and height of 1 pixel. when it gets resized, we use
+ // set its scale to the width and height of the bounds it should have to avoid layout passes
+ dropTargetView.layoutParams = FrameLayout.LayoutParams(/* width= */ 1, /* height= */ 1)
}
/** Called when the user drags to a new location. */
@@ -42,14 +74,67 @@ class DropTargetManager(
state.currentDragZone = newDragZone
if (oldDragZone != newDragZone) {
dragZoneChangedListener.onDragZoneChanged(from = oldDragZone, to = newDragZone)
+ updateDropTarget()
}
}
/** Called when the drag ended. */
fun onDragEnded() {
+ startFadeAnimation(from = dropTargetView.alpha, to = 0f) {
+ container.removeView(dropTargetView)
+ }
state = null
}
+ private fun updateDropTarget() {
+ val currentDragZone = state?.currentDragZone ?: return
+ val dropTargetBounds = currentDragZone.dropTarget
+ when {
+ dropTargetBounds == null -> startFadeAnimation(from = dropTargetView.alpha, to = 0f)
+ dropTargetView.alpha == 0f -> {
+ dropTargetView.translationX = dropTargetBounds.exactCenterX()
+ dropTargetView.translationY = dropTargetBounds.exactCenterY()
+ dropTargetView.scaleX = dropTargetBounds.width().toFloat()
+ dropTargetView.scaleY = dropTargetBounds.height().toFloat()
+ startFadeAnimation(from = 0f, to = 1f)
+ }
+ else -> startMorphAnimation(dropTargetBounds)
+ }
+ }
+
+ private fun startFadeAnimation(from: Float, to: Float, onEnd: (() -> Unit)? = null) {
+ animator?.cancel()
+ val animator = ValueAnimator.ofFloat(from, to).setDuration(ANIMATION_DURATION_MS)
+ animator.addUpdateListener { _ -> dropTargetView.alpha = animator.animatedValue as Float }
+ if (onEnd != null) {
+ animator.doOnEnd(onEnd)
+ }
+ this.animator = animator
+ animator.start()
+ }
+
+ private fun startMorphAnimation(bounds: Rect) {
+ animator?.cancel()
+ val startAlpha = dropTargetView.alpha
+ val startTx = dropTargetView.translationX
+ val startTy = dropTargetView.translationY
+ val startScaleX = dropTargetView.scaleX
+ val startScaleY = dropTargetView.scaleY
+ val animator = ValueAnimator.ofFloat(0f, 1f).setDuration(ANIMATION_DURATION_MS)
+ animator.addUpdateListener { _ ->
+ val fraction = animator.animatedValue as Float
+ dropTargetView.alpha = startAlpha + (1 - startAlpha) * fraction
+ dropTargetView.translationX = startTx + (bounds.exactCenterX() - startTx) * fraction
+ dropTargetView.translationY = startTy + (bounds.exactCenterY() - startTy) * fraction
+ dropTargetView.scaleX =
+ startScaleX + (bounds.width().toFloat() - startScaleX) * fraction
+ dropTargetView.scaleY =
+ startScaleY + (bounds.height().toFloat() - startScaleY) * fraction
+ }
+ this.animator = animator
+ animator.start()
+ }
+
/** Stores the current drag state. */
private inner class DragState(
private val dragZones: List<DragZone>,
@@ -72,7 +157,18 @@ class DropTargetManager(
interface DragZoneChangedListener {
/** An initial drag zone was set. Called when a drag starts. */
fun onInitialDragZoneSet(dragZone: DragZone)
+
/** Called when the object was dragged to a different drag zone. */
fun onDragZoneChanged(from: DragZone, to: DragZone)
}
+
+ private fun Animator.doOnEnd(onEnd: () -> Unit) {
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ onEnd()
+ }
+ }
+ )
+ }
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 643c1506e4c2..00c446c3da60 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -27,6 +27,7 @@ import android.hardware.display.DisplayManager;
import android.os.SystemProperties;
import android.view.Display;
import android.view.WindowManager;
+import android.window.DesktopExperienceFlags;
import android.window.DesktopModeFlags;
import com.android.internal.R;
@@ -226,6 +227,7 @@ public class DesktopModeStatus {
return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops);
}
+
/**
* Return {@code true} if desktop mode dev option should be shown on current device
*/
@@ -239,23 +241,22 @@ public class DesktopModeStatus {
*/
public static boolean canShowDesktopExperienceDevOption(@NonNull Context context) {
return Flags.showDesktopExperienceDevOption()
- && isInternalDisplayEligibleToHostDesktops(context);
+ && isDeviceEligibleForDesktopMode(context);
}
/** Returns if desktop mode dev option should be enabled if there is no user override. */
public static boolean shouldDevOptionBeEnabledByDefault(Context context) {
- return isInternalDisplayEligibleToHostDesktops(context)
- && Flags.enableDesktopWindowingMode();
+ return isDeviceEligibleForDesktopMode(context)
+ && Flags.enableDesktopWindowingMode();
}
/**
* Return {@code true} if desktop mode is enabled and can be entered on the current device.
*/
public static boolean canEnterDesktopMode(@NonNull Context context) {
- return (isInternalDisplayEligibleToHostDesktops(context)
- && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue()
- && (isDesktopModeSupported(context) || !enforceDeviceRestrictions())
- || isDesktopModeEnabledByDevOption(context));
+ return (isDeviceEligibleForDesktopMode(context)
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue())
+ || isDesktopModeEnabledByDevOption(context);
}
/**
@@ -271,7 +272,7 @@ public class DesktopModeStatus {
* frontend implementations).
*/
public static boolean enableMultipleDesktops(@NonNull Context context) {
- return Flags.enableMultipleDesktopsBackend()
+ return DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()
&& Flags.enableMultipleDesktopsFrontend()
&& canEnterDesktopMode(context);
}
@@ -323,25 +324,34 @@ public class DesktopModeStatus {
}
/**
- * Return {@code true} if desktop sessions is unrestricted and can be host for the device's
- * internal display.
+ * Return {@code true} if desktop mode is unrestricted and is supported on the device.
*/
- public static boolean isInternalDisplayEligibleToHostDesktops(@NonNull Context context) {
- return !enforceDeviceRestrictions() || canInternalDisplayHostDesktops(context) || (
- Flags.enableDesktopModeThroughDevOption() && isDesktopModeDevOptionSupported(
- context));
+ public static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) {
+ if (!enforceDeviceRestrictions()) {
+ return true;
+ }
+ final boolean desktopModeSupported = isDesktopModeSupported(context)
+ && canInternalDisplayHostDesktops(context);
+ final boolean desktopModeSupportedByDevOptions =
+ Flags.enableDesktopModeThroughDevOption()
+ && isDesktopModeDevOptionSupported(context);
+ return desktopModeSupported || desktopModeSupportedByDevOptions;
}
/**
* Return {@code true} if the developer option for desktop mode is unrestricted and is supported
* in the device.
*
- * Note that, if {@link #isInternalDisplayEligibleToHostDesktops(Context)} is true, then
+ * Note that, if {@link #isDeviceEligibleForDesktopMode(Context)} is true, then
* {@link #isDeviceEligibleForDesktopModeDevOption(Context)} is also true.
*/
private static boolean isDeviceEligibleForDesktopModeDevOption(@NonNull Context context) {
- return !enforceDeviceRestrictions() || isDesktopModeSupported(context)
- || isDesktopModeDevOptionSupported(context);
+ if (!enforceDeviceRestrictions()) {
+ return true;
+ }
+ final boolean desktopModeSupported = isDesktopModeSupported(context)
+ && canInternalDisplayHostDesktops(context);
+ return desktopModeSupported || isDesktopModeDevOptionSupported(context);
}
/**
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
index b48296f5f76a..759e711100c3 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java
@@ -262,6 +262,7 @@ public class SplitScreenConstants {
/** Flag applied to a transition change to identify it as a divider bar for animation. */
public static final int FLAG_IS_DIVIDER_BAR = TransitionUtil.FLAG_IS_DIVIDER_BAR;
+ public static final int FLAG_IS_DIM_LAYER = TransitionUtil.FLAG_IS_DIM_LAYER;
public static final String splitPositionToString(@SplitPosition int pos) {
switch (pos) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index c7a0401c2b88..58b46d202599 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -22,6 +22,7 @@ import static android.service.notification.NotificationListenerService.REASON_CA
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -844,6 +845,10 @@ public class BubbleController implements ConfigurationChangeListener,
mLogger.log(onLeft ? BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_APP_ICON_DROP
: BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_APP_ICON_DROP);
break;
+ case BubbleBarLocation.UpdateSource.DRAG_TASK:
+ mLogger.log(onLeft ? BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_TASK
+ : BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_TASK);
+ break;
}
}
@@ -1290,6 +1295,11 @@ public class BubbleController implements ConfigurationChangeListener,
mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width));
mStackView.onDisplaySizeChanged();
+ // TODO b/392893178: Merge the unfold and the task view transition so that we don't
+ // have to post a delayed runnable to the looper to update the bounds
+ if (mStackView.isExpanded()) {
+ mStackView.postDelayed(() -> mStackView.updateExpandedView(), 500);
+ }
}
if (newConfig.fontScale != mFontScale) {
mFontScale = newConfig.fontScale;
@@ -1590,20 +1600,34 @@ public class BubbleController implements ConfigurationChangeListener,
* Expands and selects a bubble created from a running task in a different mode.
*
* @param taskInfo the task.
+ * @param dragData optional information about the task when it is being dragged into a bubble
*/
- public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo) {
+ public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo,
+ @Nullable BubbleTransitions.DragData dragData) {
if (!BubbleAnythingFlagHelper.enableBubbleToFullscreen()) return;
Bubble b = mBubbleData.getOrCreateBubble(taskInfo); // Removes from overflow
ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", taskInfo.taskId);
+ BubbleBarLocation location = null;
+ if (dragData != null) {
+ location =
+ dragData.isReleasedOnLeft() ? BubbleBarLocation.LEFT : BubbleBarLocation.RIGHT;
+ }
if (b.isInflated()) {
- mBubbleData.setSelectedBubbleAndExpandStack(b);
+ mBubbleData.setSelectedBubbleAndExpandStack(b, location);
+ if (dragData != null && dragData.getPendingWct() != null) {
+ mTransitions.startTransition(TRANSIT_CHANGE,
+ dragData.getPendingWct(), /* handler= */ null);
+ }
} else {
+ if (location != null) {
+ setBubbleBarLocation(location, BubbleBarLocation.UpdateSource.DRAG_TASK);
+ }
b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
// Lazy init stack view when a bubble is created
ensureBubbleViewsAndWindowCreated();
mBubbleTransitions.startConvertToBubble(b, taskInfo, mExpandedViewManager,
mBubbleTaskViewFactory, mBubblePositioner, mStackView, mLayerView,
- mBubbleIconFactory, mInflateSynchronously);
+ mBubbleIconFactory, dragData, mInflateSynchronously);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
index 831f2271d500..a0c473173bf1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
@@ -156,6 +156,12 @@ public class BubbleLogger {
@UiEvent(doc = "while bubble bar is expanded, switch to another/existing bubble")
BUBBLE_BAR_BUBBLE_SWITCHED(1977),
+ @UiEvent(doc = "bubble bar moved to the left edge of the screen by dragging a task")
+ BUBBLE_BAR_MOVED_LEFT_DRAG_TASK(2146),
+
+ @UiEvent(doc = "bubble bar moved to the right edge of the screen by dragging a task")
+ BUBBLE_BAR_MOVED_RIGHT_DRAG_TASK(2147),
+
// endregion
;
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 dad627f85d95..92724178cf84 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
@@ -3548,7 +3548,7 @@ public class BubbleStackView extends FrameLayout
}
}
- private void updateExpandedView() {
+ void updateExpandedView() {
boolean isOverflowExpanded = mExpandedBubble != null
&& BubbleOverflow.KEY.equals(mExpandedBubble.getKey());
int[] paddings = mPositioner.getExpandedViewContainerPadding(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
deleted file mode 100644
index e47ac61a53dd..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.wm.shell.bubbles;
-
-import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
-
-import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.protolog.ProtoLog;
-import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
-import com.android.wm.shell.taskview.TaskView;
-
-/**
- * Handles creating and updating the {@link TaskView} associated with a {@link Bubble}.
- */
-public class BubbleTaskViewHelper {
-
- private static final String TAG = BubbleTaskViewHelper.class.getSimpleName();
-
- /**
- * Listener for users of {@link BubbleTaskViewHelper} to use to be notified of events
- * on the task.
- */
- public interface Listener {
-
- /** Called when the task is first created. */
- void onTaskCreated();
-
- /** Called when the visibility of the task changes. */
- void onContentVisibilityChanged(boolean visible);
-
- /** Called when back is pressed on the task root. */
- void onBackPressed();
-
- /** Called when task removal has started. */
- void onTaskRemovalStarted();
- }
-
- private final Context mContext;
- private final BubbleExpandedViewManager mExpandedViewManager;
- private final BubbleTaskViewHelper.Listener mListener;
- private final View mParentView;
-
- @Nullable
- private Bubble mBubble;
- @Nullable
- private PendingIntent mPendingIntent;
- @Nullable
- private TaskView mTaskView;
- private int mTaskId = INVALID_TASK_ID;
-
- private final TaskView.Listener mTaskViewListener = new TaskView.Listener() {
- private boolean mInitialized = false;
- private boolean mDestroyed = false;
-
- @Override
- public void onInitialized() {
- ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: destroyed=%b initialized=%b bubble=%s",
- mDestroyed, mInitialized, getBubbleKey());
-
- if (mDestroyed || mInitialized) {
- return;
- }
-
- // Custom options so there is no activity transition animation
- ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext,
- 0 /* enterResId */, 0 /* exitResId */);
-
- Rect launchBounds = new Rect();
- mTaskView.getBoundsOnScreen(launchBounds);
-
- // TODO: I notice inconsistencies in lifecycle
- // Post to keep the lifecycle normal
- // TODO - currently based on type, really it's what the "launch item" is.
- mParentView.post(() -> {
- ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s",
- getBubbleKey());
- try {
- options.setTaskAlwaysOnTop(true);
- options.setPendingIntentBackgroundActivityStartMode(
- MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
- final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId()
- || (mBubble.isShortcut()
- && BubbleAnythingFlagHelper.enableCreateAnyBubble()));
- if (mBubble.getPreparingTransition() != null) {
- mBubble.getPreparingTransition().surfaceCreated();
- } else if (mBubble.isApp() || mBubble.isNote()) {
- Context context =
- mContext.createContextAsUser(
- mBubble.getUser(), Context.CONTEXT_RESTRICTED);
- Intent fillInIntent = null;
- //first try get pending intent from the bubble
- PendingIntent pi = mBubble.getPendingIntent();
- if (pi == null) {
- // if null - create new one
- pi = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- mBubble.getIntent()
- .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK),
- PendingIntent.FLAG_IMMUTABLE
- | PendingIntent.FLAG_UPDATE_CURRENT,
- /* options= */ null);
- } else {
- fillInIntent = new Intent(pi.getIntent());
- fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
- }
- mTaskView.startActivity(pi, fillInIntent, options, launchBounds);
- } else if (isShortcutBubble) {
- options.setLaunchedFromBubble(true);
- options.setApplyActivityFlagsForBubbles(true);
- mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
- options, launchBounds);
- } else {
- options.setLaunchedFromBubble(true);
- if (mBubble != null) {
- mBubble.setPendingIntentActive();
- }
- final Intent fillInIntent = new Intent();
- // Apply flags to make behaviour match documentLaunchMode=always.
- fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
- fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
- mTaskView.startActivity(mPendingIntent, fillInIntent, options,
- launchBounds);
- }
- } catch (RuntimeException e) {
- // If there's a runtime exception here then there's something
- // wrong with the intent, we can't really recover / try to populate
- // the bubble again so we'll just remove it.
- Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
- + ", " + e.getMessage() + "; removing bubble");
- mExpandedViewManager.removeBubble(
- getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT);
- }
- mInitialized = true;
- });
- }
-
- @Override
- public void onReleased() {
- mDestroyed = true;
- }
-
- @Override
- public void onTaskCreated(int taskId, ComponentName name) {
- ProtoLog.d(WM_SHELL_BUBBLES, "onTaskCreated: taskId=%d bubble=%s",
- taskId, getBubbleKey());
- // The taskId is saved to use for removeTask, preventing appearance in recent tasks.
- mTaskId = taskId;
-
- if (mBubble != null && mBubble.isNote()) {
- // Let the controller know sooner what the taskId is.
- mExpandedViewManager.setNoteBubbleTaskId(mBubble.getKey(), mTaskId);
- }
-
- // With the task org, the taskAppeared callback will only happen once the task has
- // already drawn
- mListener.onTaskCreated();
- }
-
- @Override
- public void onTaskVisibilityChanged(int taskId, boolean visible) {
- mListener.onContentVisibilityChanged(visible);
- }
-
- @Override
- public void onTaskRemovalStarted(int taskId) {
- ProtoLog.d(WM_SHELL_BUBBLES, "onTaskRemovalStarted: taskId=%d bubble=%s",
- taskId, getBubbleKey());
- if (mBubble != null) {
- mExpandedViewManager.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
- }
- if (mTaskView != null) {
- mTaskView.release();
- ((ViewGroup) mParentView).removeView(mTaskView);
- mTaskView = null;
- }
- mListener.onTaskRemovalStarted();
- }
-
- @Override
- public void onBackPressedOnTaskRoot(int taskId) {
- if (mTaskId == taskId && mExpandedViewManager.isStackExpanded()) {
- mListener.onBackPressed();
- }
- }
- };
-
- public BubbleTaskViewHelper(Context context,
- BubbleExpandedViewManager expandedViewManager,
- BubbleTaskViewHelper.Listener listener,
- BubbleTaskView bubbleTaskView,
- View parent) {
- mContext = context;
- mExpandedViewManager = expandedViewManager;
- mListener = listener;
- mParentView = parent;
- mTaskView = bubbleTaskView.getTaskView();
- bubbleTaskView.setDelegateListener(mTaskViewListener);
- if (bubbleTaskView.isCreated()) {
- mTaskId = bubbleTaskView.getTaskId();
- mListener.onTaskCreated();
- }
- }
-
- /**
- * Sets the bubble or updates the bubble used to populate the view.
- *
- * @return true if the bubble is new, false if it was an update to the same bubble.
- */
- public boolean update(Bubble bubble) {
- boolean isNew = mBubble == null || didBackingContentChange(bubble);
- mBubble = bubble;
- if (isNew) {
- mPendingIntent = mBubble.getPendingIntent();
- return true;
- }
- return false;
- }
-
- /** Returns the bubble key associated with this view. */
- @Nullable
- public String getBubbleKey() {
- return mBubble != null ? mBubble.getKey() : null;
- }
-
- /** Returns the TaskView associated with this view. */
- @Nullable
- public TaskView getTaskView() {
- return mTaskView;
- }
-
- /**
- * Returns the task id associated with the task in this view. If the task doesn't exist then
- * {@link ActivityTaskManager#INVALID_TASK_ID}.
- */
- public int getTaskId() {
- return mTaskId;
- }
-
- /** Returns whether the bubble set on the helper is valid to populate the task view. */
- public boolean isValidBubble() {
- return mBubble != null && (mPendingIntent != null || mBubble.hasMetadataShortcutId());
- }
-
- // TODO (b/274980695): Is this still relevant?
- /**
- * Bubbles are backed by a pending intent or a shortcut, once the activity is
- * started we never change it / restart it on notification updates -- unless the bubble's
- * backing data switches.
- *
- * This indicates if the new bubble is backed by a different data source than what was
- * previously shown here (e.g. previously a pending intent & now a shortcut).
- *
- * @param newBubble the bubble this view is being updated with.
- * @return true if the backing content has changed.
- */
- private boolean didBackingContentChange(Bubble newBubble) {
- boolean prevWasIntentBased = mBubble != null && mPendingIntent != null;
- boolean newIsIntentBased = newBubble.getPendingIntent() != null;
- return prevWasIntentBased != newIsIntentBased;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java
new file mode 100644
index 000000000000..a38debb702dc
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.bubbles;
+
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
+
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.protolog.ProtoLog;
+import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
+import com.android.wm.shell.taskview.TaskView;
+
+/**
+ * A listener that works with task views for bubbles, manages launching the appropriate
+ * content into the task view from the bubble and sends updates of task view events back to
+ * the parent view via {@link BubbleTaskViewListener.Callback}.
+ */
+public class BubbleTaskViewListener implements TaskView.Listener {
+ private static final String TAG = BubbleTaskViewListener.class.getSimpleName();
+
+ /**
+ * Callback to let the view parent of TaskView to be notified of different events.
+ */
+ public interface Callback {
+
+ /** Called when the task is first created. */
+ void onTaskCreated();
+
+ /** Called when the visibility of the task changes. */
+ void onContentVisibilityChanged(boolean visible);
+
+ /** Called when back is pressed on the task root. */
+ void onBackPressed();
+
+ /** Called when task removal has started. */
+ void onTaskRemovalStarted();
+ }
+
+ private final Context mContext;
+ private final BubbleExpandedViewManager mExpandedViewManager;
+ private final BubbleTaskViewListener.Callback mCallback;
+ private final View mParentView;
+
+ private Bubble mBubble;
+ @Nullable
+ private PendingIntent mPendingIntent;
+ private int mTaskId = INVALID_TASK_ID;
+ private TaskView mTaskView;
+
+ private boolean mInitialized = false;
+ private boolean mDestroyed = false;
+
+ public BubbleTaskViewListener(Context context, BubbleTaskView bubbleTaskView, View parentView,
+ BubbleExpandedViewManager manager, BubbleTaskViewListener.Callback callback) {
+ mContext = context;
+ mTaskView = bubbleTaskView.getTaskView();
+ mParentView = parentView;
+ mExpandedViewManager = manager;
+ mCallback = callback;
+ bubbleTaskView.setDelegateListener(this);
+ if (bubbleTaskView.isCreated()) {
+ mTaskId = bubbleTaskView.getTaskId();
+ callback.onTaskCreated();
+ }
+ }
+
+ @Override
+ public void onInitialized() {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: destroyed=%b initialized=%b bubble=%s",
+ mDestroyed, mInitialized, getBubbleKey());
+
+ if (mDestroyed || mInitialized) {
+ return;
+ }
+
+ // Custom options so there is no activity transition animation
+ ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext,
+ 0 /* enterResId */, 0 /* exitResId */);
+
+ Rect launchBounds = new Rect();
+ mTaskView.getBoundsOnScreen(launchBounds);
+
+ // TODO: I notice inconsistencies in lifecycle
+ // Post to keep the lifecycle normal
+ // TODO - currently based on type, really it's what the "launch item" is.
+ mParentView.post(() -> {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s",
+ getBubbleKey());
+ try {
+ options.setTaskAlwaysOnTop(true);
+ options.setPendingIntentBackgroundActivityStartMode(
+ MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
+ final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId()
+ || (mBubble.isShortcut()
+ && BubbleAnythingFlagHelper.enableCreateAnyBubble()));
+ if (mBubble.getPreparingTransition() != null) {
+ mBubble.getPreparingTransition().surfaceCreated();
+ } else if (mBubble.isApp() || mBubble.isNote()) {
+ Context context =
+ mContext.createContextAsUser(
+ mBubble.getUser(), Context.CONTEXT_RESTRICTED);
+ Intent fillInIntent = null;
+ // First try get pending intent from the bubble
+ PendingIntent pi = mBubble.getPendingIntent();
+ if (pi == null) {
+ // If null - create new one
+ pi = PendingIntent.getActivity(
+ context,
+ /* requestCode= */ 0,
+ mBubble.getIntent()
+ .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK),
+ PendingIntent.FLAG_IMMUTABLE
+ | PendingIntent.FLAG_UPDATE_CURRENT,
+ /* options= */ null);
+ } else {
+ fillInIntent = new Intent(pi.getIntent());
+ fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+ mTaskView.startActivity(pi, fillInIntent, options, launchBounds);
+ } else if (isShortcutBubble) {
+ options.setLaunchedFromBubble(true);
+ options.setApplyActivityFlagsForBubbles(true);
+ mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
+ options, launchBounds);
+ } else {
+ options.setLaunchedFromBubble(true);
+ if (mBubble != null) {
+ mBubble.setPendingIntentActive();
+ }
+ final Intent fillInIntent = new Intent();
+ // Apply flags to make behaviour match documentLaunchMode=always.
+ fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
+ fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ mTaskView.startActivity(mPendingIntent, fillInIntent, options,
+ launchBounds);
+ }
+ } catch (RuntimeException e) {
+ // If there's a runtime exception here then there's something
+ // wrong with the intent, we can't really recover / try to populate
+ // the bubble again so we'll just remove it.
+ Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
+ + ", " + e.getMessage() + "; removing bubble");
+ mExpandedViewManager.removeBubble(
+ getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT);
+ }
+ mInitialized = true;
+ });
+ }
+
+ @Override
+ public void onReleased() {
+ mDestroyed = true;
+ }
+
+ @Override
+ public void onTaskCreated(int taskId, ComponentName name) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onTaskCreated: taskId=%d bubble=%s",
+ taskId, getBubbleKey());
+ // The taskId is saved to use for removeTask, preventing appearance in recent tasks.
+ mTaskId = taskId;
+
+ if (mBubble != null && mBubble.isNote()) {
+ // Let the controller know sooner what the taskId is.
+ mExpandedViewManager.setNoteBubbleTaskId(mBubble.getKey(), mTaskId);
+ }
+
+ // With the task org, the taskAppeared callback will only happen once the task has
+ // already drawn
+ mCallback.onTaskCreated();
+ }
+
+ @Override
+ public void onTaskVisibilityChanged(int taskId, boolean visible) {
+ mCallback.onContentVisibilityChanged(visible);
+ }
+
+ @Override
+ public void onTaskRemovalStarted(int taskId) {
+ ProtoLog.d(WM_SHELL_BUBBLES, "onTaskRemovalStarted: taskId=%d bubble=%s",
+ taskId, getBubbleKey());
+ if (mBubble != null) {
+ mExpandedViewManager.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+ }
+ if (mTaskView != null) {
+ mTaskView.release();
+ ((ViewGroup) mParentView).removeView(mTaskView);
+ mTaskView = null;
+ }
+ mCallback.onTaskRemovalStarted();
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(int taskId) {
+ if (mTaskId == taskId && mExpandedViewManager.isStackExpanded()) {
+ mCallback.onBackPressed();
+ }
+ }
+
+ /**
+ * Sets the bubble or updates the bubble used to populate the view.
+ *
+ * @return true if the bubble is new or if the launch content of the bubble changed from the
+ * previous bubble.
+ */
+ public boolean setBubble(Bubble bubble) {
+ boolean isNew = mBubble == null || didBackingContentChange(bubble);
+ mBubble = bubble;
+ if (isNew) {
+ mPendingIntent = mBubble.getPendingIntent();
+ }
+ return isNew;
+ }
+
+ /** Returns the TaskView associated with this view. */
+ @Nullable
+ public TaskView getTaskView() {
+ return mTaskView;
+ }
+
+ /**
+ * Returns the task id associated with the task in this view. If the task doesn't exist then
+ * {@link ActivityTaskManager#INVALID_TASK_ID}.
+ */
+ public int getTaskId() {
+ return mTaskId;
+ }
+
+ private String getBubbleKey() {
+ return mBubble != null ? mBubble.getKey() : "";
+ }
+
+ // TODO (b/274980695): Is this still relevant?
+ /**
+ * Bubbles are backed by a pending intent or a shortcut, once the activity is
+ * started we never change it / restart it on notification updates -- unless the bubble's
+ * backing data switches.
+ *
+ * This indicates if the new bubble is backed by a different data source than what was
+ * previously shown here (e.g. previously a pending intent & now a shortcut).
+ *
+ * @param newBubble the bubble this view is being updated with.
+ * @return true if the backing content has changed.
+ */
+ private boolean didBackingContentChange(Bubble newBubble) {
+ boolean prevWasIntentBased = mBubble != null && mPendingIntent != null;
+ boolean newIsIntentBased = newBubble.getPendingIntent() != null;
+ return prevWasIntentBased != newIsIntentBased;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java
index df8b4fd12540..a676f41baafe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java
@@ -22,6 +22,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.View.INVISIBLE;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -92,10 +94,10 @@ public class BubbleTransitions {
BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory,
BubblePositioner positioner, BubbleStackView stackView,
BubbleBarLayerView layerView, BubbleIconFactory iconFactory,
- boolean inflateSync) {
+ DragData dragData, boolean inflateSync) {
return new ConvertToBubble(bubble, taskInfo, mContext,
expandedViewManager, factory, positioner, stackView, layerView, iconFactory,
- inflateSync);
+ dragData, inflateSync);
}
/**
@@ -149,43 +151,92 @@ public class BubbleTransitions {
}
/**
+ * Information about the task when it is being dragged to a bubble
+ */
+ public static class DragData {
+ private final Rect mBounds;
+ private final WindowContainerTransaction mPendingWct;
+ private final boolean mReleasedOnLeft;
+
+ /**
+ * @param bounds bounds of the dragged task when the drag was released
+ * @param wct pending operations to be applied when finishing the drag
+ * @param releasedOnLeft true if the bubble was released in the left drop target
+ */
+ public DragData(@Nullable Rect bounds, @Nullable WindowContainerTransaction wct,
+ boolean releasedOnLeft) {
+ mBounds = bounds;
+ mPendingWct = wct;
+ mReleasedOnLeft = releasedOnLeft;
+ }
+
+ /**
+ * @return bounds of the dragged task when the drag was released
+ */
+ @Nullable
+ public Rect getBounds() {
+ return mBounds;
+ }
+
+ /**
+ * @return pending operations to be applied when finishing the drag
+ */
+ @Nullable
+ public WindowContainerTransaction getPendingWct() {
+ return mPendingWct;
+ }
+
+ /**
+ * @return true if the bubble was released in the left drop target
+ */
+ public boolean isReleasedOnLeft() {
+ return mReleasedOnLeft;
+ }
+ }
+
+ /**
* BubbleTransition that coordinates the process of a non-bubble task becoming a bubble. The
* steps are as follows:
*
* 1. Start inflating the bubble view
* 2. Once inflated (but not-yet visible), tell WM to do the shell-transition.
- * 3. Transition becomes ready, so notify Launcher
- * 4. Launcher responds with showExpandedView which calls continueExpand() to make view visible
- * 5. Surface is created which kicks off actual animation
+ * 3. When the transition becomes ready, notify Launcher in parallel
+ * 4. Wait for surface to be created
+ * 5. Once surface is ready, animate the task to a bubble
*
- * So, constructor -> onInflated -> startAnimation -> continueExpand -> surfaceCreated.
+ * While the animation is pending, we keep a reference to the pending transition in the bubble.
+ * This allows us to check in other parts of the code that this bubble will be shown via the
+ * transition animation.
*
- * continueExpand and surfaceCreated are set-up to happen in either order, though, to support
- * UX/timing adjustments.
+ * startAnimation, continueExpand and surfaceCreated are set-up to happen in either order,
+ * to support UX/timing adjustments.
*/
@VisibleForTesting
class ConvertToBubble implements Transitions.TransitionHandler, BubbleTransition {
final BubbleBarLayerView mLayerView;
Bubble mBubble;
+ @Nullable DragData mDragData;
IBinder mTransition;
Transitions.TransitionFinishCallback mFinishCb;
WindowContainerTransaction mFinishWct = null;
final Rect mStartBounds = new Rect();
SurfaceControl mSnapshot = null;
TaskInfo mTaskInfo;
- boolean mFinishedExpand = false;
BubbleViewProvider mPriorBubble = null;
+ private final TransitionProgress mTransitionProgress = new TransitionProgress();
private SurfaceControl.Transaction mFinishT;
private SurfaceControl mTaskLeash;
ConvertToBubble(Bubble bubble, TaskInfo taskInfo, Context context,
BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory,
BubblePositioner positioner, BubbleStackView stackView,
- BubbleBarLayerView layerView, BubbleIconFactory iconFactory, boolean inflateSync) {
+ BubbleBarLayerView layerView, BubbleIconFactory iconFactory,
+ @Nullable DragData dragData, boolean inflateSync) {
mBubble = bubble;
mTaskInfo = taskInfo;
mLayerView = layerView;
+ mDragData = dragData;
mBubble.setInflateSynchronously(inflateSync);
mBubble.setPreparingTransition(this);
mBubble.inflate(
@@ -208,6 +259,9 @@ public class BubbleTransitions {
final Rect launchBounds = new Rect();
mLayerView.getExpandedViewRestBounds(launchBounds);
WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (mDragData != null && mDragData.getPendingWct() != null) {
+ wct.merge(mDragData.getPendingWct(), true);
+ }
if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
if (mTaskInfo.getParentTaskId() != INVALID_TASK_ID) {
wct.reparent(mTaskInfo.token, null, true);
@@ -226,7 +280,7 @@ public class BubbleTransitions {
state.mVisible = true;
}
mTaskViewTransitions.enqueueExternal(tv.getController(), () -> {
- mTransition = mTransitions.startTransition(TRANSIT_CHANGE, wct, this);
+ mTransition = mTransitions.startTransition(TRANSIT_CONVERT_TO_BUBBLE, wct, this);
return mTransition;
});
}
@@ -292,6 +346,11 @@ public class BubbleTransitions {
}
mFinishCb = finishCallback;
+ if (mDragData != null && mDragData.getBounds() != null) {
+ // Override start bounds with the dragged task bounds
+ mStartBounds.set(mDragData.getBounds());
+ }
+
// Now update state (and talk to launcher) in parallel with snapshot stuff
mBubbleData.notificationEntryUpdated(mBubble, /* suppressFlyout= */ true,
/* showInShade= */ false);
@@ -303,15 +362,22 @@ public class BubbleTransitions {
mStartBounds.left - info.getRoot(0).getOffset().x,
mStartBounds.top - info.getRoot(0).getOffset().y);
startTransaction.setLayer(mSnapshot, Integer.MAX_VALUE);
+
+ BubbleBarExpandedView bbev = mBubble.getBubbleBarExpandedView();
+ if (bbev != null) {
+ // Corners get reset during the animation. Add them back
+ startTransaction.setCornerRadius(mSnapshot, bbev.getRestingCornerRadius());
+ }
+
startTransaction.apply();
mTaskViewTransitions.onExternalDone(transition);
+ mTransitionProgress.setTransitionReady();
+ startExpandAnim();
return true;
}
- @Override
- public void continueExpand() {
- mFinishedExpand = true;
+ private void startExpandAnim() {
final boolean animate = mLayerView.canExpandView(mBubble);
if (animate) {
mPriorBubble = mLayerView.prepareConvertedView(mBubble);
@@ -322,19 +388,25 @@ public class BubbleTransitions {
mLayerView.removeView(priorView);
mPriorBubble = null;
}
- if (!animate || mBubble.getTaskView().getSurfaceControl() != null) {
+ if (!animate || mTransitionProgress.isReadyToAnimate()) {
playAnimation(animate);
}
}
@Override
+ public void continueExpand() {
+ mTransitionProgress.setReadyToExpand();
+ }
+
+ @Override
public void surfaceCreated() {
+ mTransitionProgress.setSurfaceReady();
mMainExecutor.execute(() -> {
final TaskViewTaskController tvc = mBubble.getTaskView().getController();
final TaskViewRepository.TaskViewState state = mRepository.byTaskView(tvc);
if (state == null) return;
state.mVisible = true;
- if (mFinishedExpand) {
+ if (mTransitionProgress.isReadyToAnimate()) {
playAnimation(true /* animate */);
}
});
@@ -350,9 +422,6 @@ public class BubbleTransitions {
mFinishWct = null;
}
- // Preparation is complete.
- mBubble.setPreparingTransition(null);
-
if (animate) {
mLayerView.animateConvert(startT, mStartBounds, mSnapshot, mTaskLeash, () -> {
mFinishCb.onTransitionFinished(mFinishWct);
@@ -364,6 +433,42 @@ public class BubbleTransitions {
mFinishCb = null;
}
}
+
+ /**
+ * Keeps track of internal state of different steps of this BubbleTransition.
+ */
+ private class TransitionProgress {
+ private boolean mTransitionReady;
+ private boolean mReadyToExpand;
+ private boolean mSurfaceReady;
+
+ void setTransitionReady() {
+ mTransitionReady = true;
+ onUpdate();
+ }
+
+ void setReadyToExpand() {
+ mReadyToExpand = true;
+ onUpdate();
+ }
+
+ void setSurfaceReady() {
+ mSurfaceReady = true;
+ onUpdate();
+ }
+
+ boolean isReadyToAnimate() {
+ // Animation only depends on transition and surface state
+ return mTransitionReady && mSurfaceReady;
+ }
+
+ private void onUpdate() {
+ if (mTransitionReady && mReadyToExpand && mSurfaceReady) {
+ // Clear the transition from bubble when all the steps are ready
+ mBubble.setPreparingTransition(null);
+ }
+ }
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 6798a88a6da7..d93dbc3c15d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -43,9 +43,10 @@ import com.android.wm.shell.bubbles.BubbleLogger;
import com.android.wm.shell.bubbles.BubbleOverflowContainerView;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleTaskView;
-import com.android.wm.shell.bubbles.BubbleTaskViewHelper;
+import com.android.wm.shell.bubbles.BubbleTaskViewListener;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.bubbles.RegionSamplingProvider;
+import com.android.wm.shell.dagger.HasWMComponent;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.handles.RegionSamplingHelper;
import com.android.wm.shell.taskview.TaskView;
@@ -56,7 +57,7 @@ import java.util.function.Supplier;
import javax.inject.Inject;
/** Expanded view of a bubble when it's part of the bubble bar. */
-public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskViewHelper.Listener {
+public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskViewListener.Callback {
/**
* The expanded view listener notifying the {@link BubbleBarLayerView} about the internal
* actions and events
@@ -110,7 +111,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
private BubbleExpandedViewManager mManager;
private BubblePositioner mPositioner;
private boolean mIsOverflow;
- private BubbleTaskViewHelper mBubbleTaskViewHelper;
+ private BubbleTaskViewListener mBubbleTaskViewListener;
private BubbleBarMenuViewController mMenuViewController;
@Nullable
private Supplier<Rect> mLayerBoundsSupplier;
@@ -205,6 +206,9 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
protected void onFinishInflate() {
super.onFinishInflate();
Context context = getContext();
+ if (context instanceof HasWMComponent) {
+ ((HasWMComponent) context).getWMComponent().inject(this);
+ }
setElevation(getResources().getDimensionPixelSize(R.dimen.bubble_elevation));
mCaptionHeight = context.getResources().getDimensionPixelSize(
R.dimen.bubble_bar_expanded_view_caption_height);
@@ -246,9 +250,10 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
mHandleView.setVisibility(View.GONE);
} else {
mTaskView = bubbleTaskView.getTaskView();
- mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, expandedViewManager,
- /* listener= */ this, bubbleTaskView,
- /* viewParent= */ this);
+ mBubbleTaskViewListener = new BubbleTaskViewListener(mContext, bubbleTaskView,
+ /* viewParent= */ this,
+ expandedViewManager,
+ /* callback= */ this);
// if the task view is already attached to a parent we need to remove it
if (mTaskView.getParent() != null) {
@@ -535,13 +540,15 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
/** Updates the bubble shown in the expanded view. */
public void update(Bubble bubble) {
mBubble = bubble;
- mBubbleTaskViewHelper.update(bubble);
+ mBubbleTaskViewListener.setBubble(bubble);
mMenuViewController.updateMenu(bubble);
}
/** The task id of the activity shown in the task view, if it exists. */
public int getTaskId() {
- return mBubbleTaskViewHelper != null ? mBubbleTaskViewHelper.getTaskId() : INVALID_TASK_ID;
+ return mBubbleTaskViewListener != null
+ ? mBubbleTaskViewListener.getTaskId()
+ : INVALID_TASK_ID;
}
/** Sets layer bounds supplier used for obscured touchable region of task view */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index 4c3bde9b2b3a..97184c859d4d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -67,6 +67,7 @@ public class DisplayController {
private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>();
private final Map<Integer, RectF> mUnpopulatedDisplayBounds = new HashMap<>();
+ private DisplayTopology mDisplayTopology;
public DisplayController(Context context, IWindowManager wmService, ShellInit shellInit,
ShellExecutor mainExecutor, DisplayManager displayManager) {
@@ -157,6 +158,7 @@ public class DisplayController {
for (int i = 0; i < mDisplays.size(); ++i) {
listener.onDisplayAdded(mDisplays.keyAt(i));
}
+ listener.onTopologyChanged(mDisplayTopology);
}
}
@@ -245,6 +247,7 @@ public class DisplayController {
if (topology == null) {
return;
}
+ mDisplayTopology = topology;
SparseArray<RectF> absoluteBounds = topology.getAbsoluteBounds();
mUnpopulatedDisplayBounds.clear();
for (int i = 0; i < absoluteBounds.size(); ++i) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/WindowContainerTransactionSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/WindowContainerTransactionSupplier.kt
new file mode 100644
index 000000000000..a1d700af5569
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/WindowContainerTransactionSupplier.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2025 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.wm.shell.common
+
+import android.window.WindowContainerTransaction
+import com.android.wm.shell.dagger.WMSingleton
+import java.util.function.Supplier
+import javax.inject.Inject
+
+/**
+ * An Injectable [Supplier<WindowContainerTransaction>]. This can be used in place of kotlin default
+ * parameters values [builder = ::WindowContainerTransaction] which requires the
+ * [@JvmOverloads] annotation to make this available in Java.
+ * This can be used every time a component needs the dependency to the default [Supplier] for
+ * [WindowContainerTransaction]s.
+ */
+@WMSingleton
+class WindowContainerTransactionSupplier @Inject constructor(
+) : Supplier<WindowContainerTransaction> {
+ override fun get(): WindowContainerTransaction = WindowContainerTransaction()
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
index c10c2c905c97..c6afc313b239 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
@@ -81,8 +81,8 @@ public class PipDesktopState {
return false;
}
- /** Returns whether PiP is exiting while we're in a Desktop Mode session. */
- private boolean isPipExitingToDesktopMode() {
+ /** Returns whether PiP is active in a display that is in active Desktop Mode session. */
+ public boolean isPipInDesktopMode() {
// Early return if PiP in Desktop Windowing is not supported.
if (!isDesktopWindowingPipEnabled()) {
return false;
@@ -137,7 +137,7 @@ public class PipDesktopState {
// 1) If the display windowing mode is freeform, set windowing mode to UNDEFINED so it will
// resolve the windowing mode to the display's windowing mode.
// 2) If the display windowing mode is not FREEFORM, set windowing mode to FREEFORM.
- if (isPipExitingToDesktopMode()) {
+ if (isPipInDesktopMode()) {
if (isDisplayInFreeform()) {
return WINDOWING_MODE_UNDEFINED;
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/CenterParallaxSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/CenterParallaxSpec.java
new file mode 100644
index 000000000000..fb2a324375b6
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/CenterParallaxSpec.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.common.split;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Calculation class, used when
+ * {@link com.android.wm.shell.common.split.SplitLayout#PARALLAX_ALIGN_CENTER} is the desired
+ * parallax effect.
+ */
+public class CenterParallaxSpec implements ParallaxSpec {
+ @Override
+ public void getParallax(Point retreatingOut, Point advancingOut, int position,
+ DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
+ Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
+ Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
+ if (isLeftRightSplit) {
+ retreatingOut.x = (retreatingSurface.width() - retreatingContent.width()) / 2;
+ } else {
+ retreatingOut.y = (retreatingSurface.height() - retreatingContent.height()) / 2;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DismissingParallaxSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DismissingParallaxSpec.java
new file mode 100644
index 000000000000..39ecbb379d7d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DismissingParallaxSpec.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.common.split;
+
+import static android.view.WindowManager.DOCKED_INVALID;
+
+import static com.android.wm.shell.shared.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.WindowManager;
+
+/**
+ * Calculation class, used when
+ * {@link com.android.wm.shell.common.split.SplitLayout#PARALLAX_DISMISSING} is the desired parallax
+ * effect.
+ */
+public class DismissingParallaxSpec implements ParallaxSpec {
+ @Override
+ public void getParallax(Point retreatingOut, Point advancingOut, int position,
+ DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
+ Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
+ Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
+ if (dimmingSide == DOCKED_INVALID) {
+ return;
+ }
+
+ float progressTowardScreenEdge =
+ Math.max(0, Math.min(snapAlgorithm.calculateDismissingFraction(position), 1f));
+ int totalDismissingDistance = 0;
+ if (position < snapAlgorithm.getFirstSplitTarget().getPosition()) {
+ totalDismissingDistance = snapAlgorithm.getDismissStartTarget().getPosition()
+ - snapAlgorithm.getFirstSplitTarget().getPosition();
+ } else if (position > snapAlgorithm.getLastSplitTarget().getPosition()) {
+ totalDismissingDistance = snapAlgorithm.getLastSplitTarget().getPosition()
+ - snapAlgorithm.getDismissEndTarget().getPosition();
+ }
+
+ float parallaxFraction =
+ calculateParallaxDismissingFraction(progressTowardScreenEdge, dimmingSide);
+ if (isLeftRightSplit) {
+ retreatingOut.x = (int) (parallaxFraction * totalDismissingDistance);
+ } else {
+ retreatingOut.y = (int) (parallaxFraction * totalDismissingDistance);
+ }
+ }
+
+ /**
+ * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
+ * slowing down parallax effect
+ */
+ private float calculateParallaxDismissingFraction(float fraction, int dockSide) {
+ float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+
+ // Less parallax at the top, just because.
+ if (dockSide == WindowManager.DOCKED_TOP) {
+ result /= 2f;
+ }
+ return result;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
index 2f5afcaa907b..5b2dd97a338f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
@@ -465,5 +465,9 @@ public class DividerSnapAlgorithm {
this.snapPosition = snapPosition;
this.distanceMultiplier = distanceMultiplier;
}
+
+ public int getPosition() {
+ return position;
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/FlexParallaxSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/FlexParallaxSpec.java
new file mode 100644
index 000000000000..9fa162164e0e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/FlexParallaxSpec.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.common.split;
+
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+
+import static com.android.wm.shell.common.split.ResizingEffectPolicy.DEFAULT_OFFSCREEN_DIM;
+import static com.android.wm.shell.shared.animation.Interpolators.DIM_INTERPOLATOR;
+import static com.android.wm.shell.shared.animation.Interpolators.FAST_DIM_INTERPOLATOR;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Calculation class, used when {@link com.android.wm.shell.common.split.SplitLayout#PARALLAX_FLEX}
+ * is the desired parallax effect.
+ */
+public class FlexParallaxSpec implements ParallaxSpec {
+ final Rect mTempRect = new Rect();
+
+ @Override
+ public int getDimmingSide(int position, DividerSnapAlgorithm snapAlgorithm,
+ boolean isLeftRightSplit) {
+ if (position < snapAlgorithm.getMiddleTarget().getPosition()) {
+ return isLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP;
+ } else if (position > snapAlgorithm.getMiddleTarget().getPosition()) {
+ return isLeftRightSplit ? DOCKED_RIGHT : DOCKED_BOTTOM;
+ }
+ return DOCKED_INVALID;
+ }
+
+ /**
+ * Calculates the amount of dim to apply to a task surface moving offscreen in flexible split.
+ * In flexible split, there are two dimming "behaviors".
+ * 1) "slow dim": when moving the divider from the middle of the screen to a target at 10% or
+ * 90%, we dim the app slightly as it moves partially offscreen.
+ * 2) "fast dim": when moving the divider from a side snap target further toward the screen
+ * edge, we dim the app rapidly as it approaches the dismiss point.
+ * @return 0f = no dim applied. 1f = full black.
+ */
+ public float getDimValue(int position, DividerSnapAlgorithm snapAlgorithm) {
+ int startDismissPos = snapAlgorithm.getDismissStartTarget().getPosition();
+ int firstTargetPos = snapAlgorithm.getFirstSplitTarget().getPosition();
+ int middleTargetPos = snapAlgorithm.getMiddleTarget().getPosition();
+ int lastTargetPos = snapAlgorithm.getLastSplitTarget().getPosition();
+ int endDismissPos = snapAlgorithm.getDismissEndTarget().getPosition();
+ float progress;
+
+ if (startDismissPos <= position && position < firstTargetPos) {
+ // Divider is on the left/top (between 0% and 10% of screen), "fast dim" as it moves
+ // toward the screen edge
+ progress = (float) (firstTargetPos - position) / (firstTargetPos - startDismissPos);
+ return fastDim(progress);
+ } else if (firstTargetPos <= position && position < middleTargetPos) {
+ // Divider is between 10% and 50%, "slow dim" as it moves toward the left/top target
+ progress = (float) (middleTargetPos - position) / (middleTargetPos - firstTargetPos);
+ return slowDim(progress);
+ } else if (middleTargetPos <= position && position < lastTargetPos) {
+ // Divider is between 50% and 90%, "slow dim" as it moves toward the right/bottom target
+ progress = (float) (position - middleTargetPos) / (lastTargetPos - middleTargetPos);
+ return slowDim(progress);
+ } else if (lastTargetPos <= position && position <= endDismissPos) {
+ // Divider is on the right/bottom (between 90% and 100% of screen), "fast dim" as it
+ // moves toward screen edge
+ progress = (float) (position - lastTargetPos) / (endDismissPos - lastTargetPos);
+ return fastDim(progress);
+ }
+ return 0f;
+ }
+
+ /**
+ * Used by {@link #getDimValue} to determine the amount to dim an app. Starts at zero and ramps
+ * up to the default amount of dimming for an offscreen app,
+ * {@link ResizingEffectPolicy#DEFAULT_OFFSCREEN_DIM}.
+ */
+ private float slowDim(float progress) {
+ return DIM_INTERPOLATOR.getInterpolation(progress) * DEFAULT_OFFSCREEN_DIM;
+ }
+
+ /**
+ * Used by {@link #getDimValue} to determine the amount to dim an app. Starts at
+ * {@link ResizingEffectPolicy#DEFAULT_OFFSCREEN_DIM} and ramps up to 100% dim (full black).
+ */
+ private float fastDim(float progress) {
+ return DEFAULT_OFFSCREEN_DIM + (FAST_DIM_INTERPOLATOR.getInterpolation(progress)
+ * (1 - DEFAULT_OFFSCREEN_DIM));
+ }
+
+ @Override
+ public void getParallax(Point retreatingOut, Point advancingOut, int position,
+ DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
+ Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
+ Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
+ // Whether an app is getting pushed offscreen by the divider.
+ boolean isRetreatingOffscreen = !displayBounds.contains(retreatingSurface);
+ // Whether an app was getting pulled onscreen at the beginning of the drag.
+ boolean advancingSideStartedOffscreen = !displayBounds.contains(advancingContent);
+
+ // The simpler case when an app gets pushed offscreen (e.g. 50:50 -> 90:10)
+ if (isRetreatingOffscreen && !advancingSideStartedOffscreen) {
+ // On the left side, we use parallax to simulate the contents sticking to the
+ // divider. This is because surfaces naturally expand to the bottom and right,
+ // so when a surface's area expands, the contents stick to the left. This is
+ // correct behavior on the right-side surface, but not the left.
+ if (topLeftShrink) {
+ if (isLeftRightSplit) {
+ retreatingOut.x = retreatingSurface.width() - retreatingContent.width();
+ } else {
+ retreatingOut.y = retreatingSurface.height() - retreatingContent.height();
+ }
+ }
+ // All other cases (e.g. 10:90 -> 50:50, 10:90 -> 90:10, 10:90 -> dismiss)
+ } else {
+ mTempRect.set(retreatingSurface);
+ Point rootOffset = new Point();
+ // 10:90 -> 50:50, 10:90, or dismiss right
+ if (advancingSideStartedOffscreen) {
+ // We have to handle a complicated case here to keep the parallax smooth.
+ // When the divider crosses the 50% mark, the retreating-side app surface
+ // will start expanding offscreen. This is expected and unavoidable, but
+ // makes the parallax look disjointed. In order to preserve the illusion,
+ // we add another offset (rootOffset) to simulate the surface staying
+ // onscreen.
+ if (mTempRect.intersect(displayBounds)) {
+ if (retreatingSurface.left < displayBounds.left) {
+ rootOffset.x = displayBounds.left - retreatingSurface.left;
+ }
+ if (retreatingSurface.top < displayBounds.top) {
+ rootOffset.y = displayBounds.top - retreatingSurface.top;
+ }
+ }
+
+ // On the left side, we again have to simulate the contents sticking to the
+ // divider.
+ if (!topLeftShrink) {
+ if (isLeftRightSplit) {
+ advancingOut.x = advancingSurface.width() - advancingContent.width();
+ } else {
+ advancingOut.y = advancingSurface.height() - advancingContent.height();
+ }
+ }
+ }
+
+ // In all these cases, the shrinking app also receives a center parallax.
+ if (isLeftRightSplit) {
+ retreatingOut.x = rootOffset.x
+ + ((mTempRect.width() - retreatingContent.width()) / 2);
+ } else {
+ retreatingOut.y = rootOffset.y
+ + ((mTempRect.height() - retreatingContent.height()) / 2);
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/NoParallaxSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/NoParallaxSpec.java
new file mode 100644
index 000000000000..043b2880f28b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/NoParallaxSpec.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.common.split;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Calculation class, used when {@link com.android.wm.shell.common.split.SplitLayout#PARALLAX_NONE}
+ * is the desired parallax effect.
+ */
+public class NoParallaxSpec implements ParallaxSpec {
+ @Override
+ public void getParallax(Point retreatingOut, Point advancingOut, int position,
+ DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
+ Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
+ Rect advancingContent, int dimmingSide, boolean topLeftShrink) {
+ // no-op
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/ParallaxSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/ParallaxSpec.java
new file mode 100644
index 000000000000..84d849b3c1f9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/ParallaxSpec.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.split;
+
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+
+import static com.android.wm.shell.shared.animation.Interpolators.DIM_INTERPOLATOR;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Default interface for a set of calculation classes, used for calculating various parallax and
+ * dimming effects in split screen.
+ */
+public interface ParallaxSpec {
+ /** Returns an int indicating which side of the screen is being dimmed (if any). */
+ default int getDimmingSide(int position, DividerSnapAlgorithm snapAlgorithm,
+ boolean isLeftRightSplit) {
+ if (position < snapAlgorithm.getFirstSplitTarget().getPosition()) {
+ return isLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP;
+ } else if (position > snapAlgorithm.getLastSplitTarget().getPosition()) {
+ return isLeftRightSplit ? DOCKED_RIGHT : DOCKED_BOTTOM;
+ }
+ return DOCKED_INVALID;
+ }
+
+ /** Returns the dim amount that we'll apply to the app surface. 0f = no dim, 1f = full black */
+ default float getDimValue(int position, DividerSnapAlgorithm snapAlgorithm) {
+ float progressTowardScreenEdge =
+ Math.max(0, Math.min(snapAlgorithm.calculateDismissingFraction(position), 1f));
+ return DIM_INTERPOLATOR.getInterpolation(progressTowardScreenEdge);
+ }
+
+ /**
+ * Calculates the amount to offset app surfaces to create nice parallax effects. Writes to
+ * {@link ResizingEffectPolicy#mRetreatingSideParallax} and
+ * {@link ResizingEffectPolicy#mAdvancingSideParallax}.
+ */
+ void getParallax(Point retreatingOut, Point advancingOut, int position,
+ DividerSnapAlgorithm snapAlgorithm, boolean isLeftRightSplit, Rect displayBounds,
+ Rect retreatingSurface, Rect retreatingContent, Rect advancingSurface,
+ Rect advancingContent, int dimmingSide, boolean topLeftShrink);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/ResizingEffectPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/ResizingEffectPolicy.java
index 3f76fd0220ff..e2e1f9698a90 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/ResizingEffectPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/ResizingEffectPolicy.java
@@ -26,27 +26,32 @@ import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTE
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_DISMISSING;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_FLEX;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_NONE;
-import static com.android.wm.shell.shared.animation.Interpolators.DIM_INTERPOLATOR;
-import static com.android.wm.shell.shared.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.SurfaceControl;
-import android.view.WindowManager;
/**
* This class governs how and when parallax and dimming effects are applied to task surfaces,
* usually when the divider is being moved around by the user (or during an animation).
*/
class ResizingEffectPolicy {
+ /** The default amount to dim an app that is partially offscreen. */
+ public static float DEFAULT_OFFSCREEN_DIM = 0.32f;
+
private final SplitLayout mSplitLayout;
/** The parallax algorithm we are currently using. */
private final int mParallaxType;
+ /**
+ * A convenience class, corresponding to {@link #mParallaxType}, that performs all the
+ * calculations for parallax and dimming values.
+ */
+ private final ParallaxSpec mParallaxSpec;
int mShrinkSide = DOCKED_INVALID;
// The current dismissing side.
- int mDismissingSide = DOCKED_INVALID;
+ int mDimmingSide = DOCKED_INVALID;
/**
* A {@link Point} that stores a single x and y value, representing the parallax translation
@@ -62,7 +67,7 @@ class ResizingEffectPolicy {
final Point mAdvancingSideParallax = new Point();
// The dimming value to hint the dismissing side and progress.
- float mDismissingDimValue = 0.0f;
+ float mDimValue = 0.0f;
/**
* Content bounds for the app that the divider is moving toward. This is the content that is
@@ -95,35 +100,38 @@ class ResizingEffectPolicy {
ResizingEffectPolicy(int parallaxType, SplitLayout splitLayout) {
mParallaxType = parallaxType;
mSplitLayout = splitLayout;
+ switch (mParallaxType) {
+ case PARALLAX_DISMISSING:
+ mParallaxSpec = new DismissingParallaxSpec();
+ break;
+ case PARALLAX_ALIGN_CENTER:
+ mParallaxSpec = new CenterParallaxSpec();
+ break;
+ case PARALLAX_FLEX:
+ mParallaxSpec = new FlexParallaxSpec();
+ break;
+ case PARALLAX_NONE:
+ default:
+ mParallaxSpec = new NoParallaxSpec();
+ break;
+ }
}
/**
- * Calculates the desired parallax values and stores them in {@link #mRetreatingSideParallax}
- * and {@link #mAdvancingSideParallax}. These values will be then be applied in
- * {@link #adjustRootSurface}.
- *
- * @param position The divider's position on the screen (x-coordinate in left-right split,
- * y-coordinate in top-bottom split).
+ * Calculates the desired parallax and dimming values for a task surface and stores them in
+ * {@link #mRetreatingSideParallax}, {@link #mAdvancingSideParallax}, and
+ * {@link #mDimValue} These values will be then be applied in
+ * {@link #adjustRootSurface} and {@link #adjustDimSurface} respectively.
*/
void applyDividerPosition(
int position, boolean isLeftRightSplit, DividerSnapAlgorithm snapAlgorithm) {
- mDismissingSide = DOCKED_INVALID;
+ mDimmingSide = DOCKED_INVALID;
mRetreatingSideParallax.set(0, 0);
mAdvancingSideParallax.set(0, 0);
- mDismissingDimValue = 0;
+ mDimValue = 0;
Rect displayBounds = mSplitLayout.getRootBounds();
- int totalDismissingDistance = 0;
- if (position < snapAlgorithm.getFirstSplitTarget().position) {
- mDismissingSide = isLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP;
- totalDismissingDistance = snapAlgorithm.getDismissStartTarget().position
- - snapAlgorithm.getFirstSplitTarget().position;
- } else if (position > snapAlgorithm.getLastSplitTarget().position) {
- mDismissingSide = isLeftRightSplit ? DOCKED_RIGHT : DOCKED_BOTTOM;
- totalDismissingDistance = snapAlgorithm.getLastSplitTarget().position
- - snapAlgorithm.getDismissEndTarget().position;
- }
-
+ // Figure out which side is shrinking, and assign retreating/advancing bounds
final boolean topLeftShrink = isLeftRightSplit
? position < mSplitLayout.getTopLeftContentBounds().right
: position < mSplitLayout.getTopLeftContentBounds().bottom;
@@ -141,106 +149,20 @@ class ResizingEffectPolicy {
mAdvancingSurface.set(mSplitLayout.getTopLeftBounds());
}
- if (mDismissingSide != DOCKED_INVALID) {
- float fraction =
- Math.max(0, Math.min(snapAlgorithm.calculateDismissingFraction(position), 1f));
- mDismissingDimValue = DIM_INTERPOLATOR.getInterpolation(fraction);
- if (mParallaxType == PARALLAX_DISMISSING) {
- fraction = calculateParallaxDismissingFraction(fraction, mDismissingSide);
- if (isLeftRightSplit) {
- mRetreatingSideParallax.x = (int) (fraction * totalDismissingDistance);
- } else {
- mRetreatingSideParallax.y = (int) (fraction * totalDismissingDistance);
- }
- }
- }
-
- if (mParallaxType == PARALLAX_ALIGN_CENTER) {
- if (isLeftRightSplit) {
- mRetreatingSideParallax.x =
- (mRetreatingSurface.width() - mRetreatingContent.width()) / 2;
- } else {
- mRetreatingSideParallax.y =
- (mRetreatingSurface.height() - mRetreatingContent.height()) / 2;
- }
- } else if (mParallaxType == PARALLAX_FLEX) {
- // Whether an app is getting pushed offscreen by the divider.
- boolean isRetreatingOffscreen = !displayBounds.contains(mRetreatingSurface);
- // Whether an app was getting pulled onscreen at the beginning of the drag.
- boolean advancingSideStartedOffscreen = !displayBounds.contains(mAdvancingContent);
+ // Figure out if we should be dimming one side
+ mDimmingSide = mParallaxSpec.getDimmingSide(position, snapAlgorithm, isLeftRightSplit);
- // The simpler case when an app gets pushed offscreen (e.g. 50:50 -> 90:10)
- if (isRetreatingOffscreen && !advancingSideStartedOffscreen) {
- // On the left side, we use parallax to simulate the contents sticking to the
- // divider. This is because surfaces naturally expand to the bottom and right,
- // so when a surface's area expands, the contents stick to the left. This is
- // correct behavior on the right-side surface, but not the left.
- if (topLeftShrink) {
- if (isLeftRightSplit) {
- mRetreatingSideParallax.x =
- mRetreatingSurface.width() - mRetreatingContent.width();
- } else {
- mRetreatingSideParallax.y =
- mRetreatingSurface.height() - mRetreatingContent.height();
- }
- }
- // All other cases (e.g. 10:90 -> 50:50, 10:90 -> 90:10, 10:90 -> dismiss)
- } else {
- mTempRect.set(mRetreatingSurface);
- Point rootOffset = new Point();
- // 10:90 -> 50:50, 10:90, or dismiss right
- if (advancingSideStartedOffscreen) {
- // We have to handle a complicated case here to keep the parallax smooth.
- // When the divider crosses the 50% mark, the retreating-side app surface
- // will start expanding offscreen. This is expected and unavoidable, but
- // makes the parallax look disjointed. In order to preserve the illusion,
- // we add another offset (rootOffset) to simulate the surface staying
- // onscreen.
- mTempRect.intersect(displayBounds);
- if (mRetreatingSurface.left < displayBounds.left) {
- rootOffset.x = displayBounds.left - mRetreatingSurface.left;
- }
- if (mRetreatingSurface.top < displayBounds.top) {
- rootOffset.y = displayBounds.top - mRetreatingSurface.top;
- }
-
- // On the left side, we again have to simulate the contents sticking to the
- // divider.
- if (!topLeftShrink) {
- if (isLeftRightSplit) {
- mAdvancingSideParallax.x =
- mAdvancingSurface.width() - mAdvancingContent.width();
- } else {
- mAdvancingSideParallax.y =
- mAdvancingSurface.height() - mAdvancingContent.height();
- }
- }
- }
-
- // In all these cases, the shrinking app also receives a center parallax.
- if (isLeftRightSplit) {
- mRetreatingSideParallax.x = rootOffset.x
- + ((mTempRect.width() - mRetreatingContent.width()) / 2);
- } else {
- mRetreatingSideParallax.y = rootOffset.y
- + ((mTempRect.height() - mRetreatingContent.height()) / 2);
- }
- }
+ // If so, calculate dimming
+ if (mDimmingSide != DOCKED_INVALID) {
+ mDimValue = mParallaxSpec.getDimValue(position, snapAlgorithm);
}
- }
- /**
- * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
- * slowing down parallax effect
- */
- private float calculateParallaxDismissingFraction(float fraction, int dockSide) {
- float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
-
- // Less parallax at the top, just because.
- if (dockSide == WindowManager.DOCKED_TOP) {
- result /= 2f;
- }
- return result;
+ // Calculate parallax and modify mRetreatingSideParallax and mAdvancingSideParallax, for use
+ // in adjustRootSurface().
+ mParallaxSpec.getParallax(mRetreatingSideParallax, mAdvancingSideParallax, position,
+ snapAlgorithm, isLeftRightSplit, displayBounds, mRetreatingSurface,
+ mRetreatingContent, mAdvancingSurface, mAdvancingContent, mDimmingSide,
+ topLeftShrink);
}
/** Applies the calculated parallax and dimming values to task surfaces. */
@@ -250,7 +172,7 @@ class ResizingEffectPolicy {
SurfaceControl advancingLeash = null;
if (mParallaxType == PARALLAX_DISMISSING) {
- switch (mDismissingSide) {
+ switch (mDimmingSide) {
case DOCKED_TOP:
case DOCKED_LEFT:
retreatingLeash = leash1;
@@ -303,14 +225,17 @@ class ResizingEffectPolicy {
void adjustDimSurface(SurfaceControl.Transaction t,
SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
SurfaceControl targetDimLayer;
- switch (mDismissingSide) {
+ SurfaceControl oppositeDimLayer;
+ switch (mDimmingSide) {
case DOCKED_TOP:
case DOCKED_LEFT:
targetDimLayer = dimLayer1;
+ oppositeDimLayer = dimLayer2;
break;
case DOCKED_BOTTOM:
case DOCKED_RIGHT:
targetDimLayer = dimLayer2;
+ oppositeDimLayer = dimLayer1;
break;
case DOCKED_INVALID:
default:
@@ -318,7 +243,9 @@ class ResizingEffectPolicy {
t.setAlpha(dimLayer2, 0).hide(dimLayer2);
return;
}
- t.setAlpha(targetDimLayer, mDismissingDimValue)
- .setVisibility(targetDimLayer, mDismissingDimValue > 0.001f);
+ t.setAlpha(targetDimLayer, mDimValue)
+ .setVisibility(targetDimLayer, mDimValue > 0.001f);
+ t.setAlpha(oppositeDimLayer, 0f)
+ .setVisibility(oppositeDimLayer, false);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index bd89f5cf45f6..708e26cc5546 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -128,6 +128,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
// The touch layer is on a stage root, and is sibling with things like the app activity itself
// and the app veil. We want it to be above all those.
public static final int RESTING_TOUCH_LAYER = Integer.MAX_VALUE;
+ // The dim layer is also on the stage root, and stays under the touch layer.
+ public static final int RESTING_DIM_LAYER = RESTING_TOUCH_LAYER - 1;
// Animation specs for the swap animation
private static final int SWAP_ANIMATION_TOTAL_DURATION = 500;
@@ -1201,6 +1203,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
// Resets layer of divider bar to make sure it is always on top.
t.setLayer(dividerLeash, RESTING_DIVIDER_LAYER);
}
+ if (dimLayer1 != null) {
+ t.setLayer(dimLayer1, RESTING_DIM_LAYER);
+ }
+ if (dimLayer2 != null) {
+ t.setLayer(dimLayer2, RESTING_DIM_LAYER);
+ }
copyTopLeftRefBounds(mTempRect);
t.setPosition(leash1, mTempRect.left, mTempRect.top)
.setWindowCrop(leash1, mTempRect.width(), mTempRect.height());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitState.java
index d1d133d16ae4..ad0e7fc187e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitState.java
@@ -57,4 +57,9 @@ public class SplitState {
public List<RectF> getLayout(@SplitScreenState int state) {
return mSplitSpec.getSpec(state);
}
+
+ /** Returns the layout associated with the current split state. */
+ public List<RectF> getCurrentLayout() {
+ return getLayout(mState);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListener.kt
new file mode 100644
index 000000000000..bdffcf51e7d4
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListener.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2025 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.wm.shell.compatui.letterbox.events
+
+import android.graphics.Rect
+import android.view.GestureDetector
+import android.view.MotionEvent
+import android.window.WindowContainerToken
+import com.android.wm.shell.common.WindowContainerTransactionSupplier
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TRANSIT_MOVE_LETTERBOX_REACHABILITY
+
+/**
+ * [GestureDetector.SimpleOnGestureListener] implementation which receives events from the
+ * Letterbox Input surface, understands the type of event and filter them based on the current
+ * letterbox position.
+ */
+class ReachabilityGestureListener(
+ private val taskId: Int,
+ private val token: WindowContainerToken?,
+ private val transitions: Transitions,
+ private val animationHandler: Transitions.TransitionHandler,
+ private val wctSupplier: WindowContainerTransactionSupplier
+) : GestureDetector.SimpleOnGestureListener() {
+
+ // The current letterbox bounds. Double tap events are ignored when happening in these bounds.
+ private val activityBounds = Rect()
+
+ override fun onDoubleTap(e: MotionEvent): Boolean {
+ val x = e.rawX.toInt()
+ val y = e.rawY.toInt()
+ if (!activityBounds.contains(x, y)) {
+ val wct = wctSupplier.get().apply {
+ setReachabilityOffset(token!!, taskId, x, y)
+ }
+ transitions.startTransition(
+ TRANSIT_MOVE_LETTERBOX_REACHABILITY,
+ wct,
+ animationHandler
+ )
+ return true
+ }
+ return false
+ }
+
+ /**
+ * Updates the bounds for the letterboxed activity.
+ */
+ fun updateActivityBounds(newActivityBounds: Rect) {
+ activityBounds.set(newActivityBounds)
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerFactory.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerFactory.kt
new file mode 100644
index 000000000000..5e9fe09bc840
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerFactory.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2025 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.wm.shell.compatui.letterbox.events
+
+import android.window.WindowContainerToken
+import com.android.wm.shell.common.WindowContainerTransactionSupplier
+import com.android.wm.shell.dagger.WMSingleton
+import com.android.wm.shell.transition.Transitions
+import javax.inject.Inject
+
+/**
+ * A Factory for [ReachabilityGestureListener].
+ */
+@WMSingleton
+class ReachabilityGestureListenerFactory @Inject constructor(
+ private val transitions: Transitions,
+ private val animationHandler: Transitions.TransitionHandler,
+ private val wctSupplier: WindowContainerTransactionSupplier
+) {
+ /**
+ * @return a [ReachabilityGestureListener] implementation to listen to double tap events and
+ * creating the related [WindowContainerTransaction] to handle the transition.
+ */
+ fun createReachabilityGestureListener(
+ taskId: Int,
+ token: WindowContainerToken?
+ ): ReachabilityGestureListener =
+ ReachabilityGestureListener(taskId, token, transitions, animationHandler, wctSupplier)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
index aebd94fc173a..34d840eed3f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
@@ -92,7 +92,7 @@ public class TvWMShellModule {
MultiInstanceHelper multiInstanceHelper,
SplitState splitState,
@ShellMainThread ShellExecutor mainExecutor,
- Handler mainHandler,
+ @ShellMainThread Handler mainHandler,
SystemWindows systemWindows) {
return new TvSplitScreenController(context, shellInit, shellCommandHandler, shellController,
shellTaskOrganizer, syncQueue, rootTDAOrganizer, displayController,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 5de49b757128..2fd8c27d5970 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -134,6 +134,7 @@ import com.android.wm.shell.recents.RecentsTransitionHandler;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.annotations.ShellAnimationThread;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
+import com.android.wm.shell.shared.annotations.ShellDesktopThread;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
@@ -750,6 +751,7 @@ public abstract class WMShellModule {
MultiInstanceHelper multiInstanceHelper,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
+ @ShellDesktopThread ShellExecutor desktopExecutor,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
Optional<RecentTasksController> recentTasksController,
InteractionJankMonitor interactionJankMonitor,
@@ -757,7 +759,6 @@ public abstract class WMShellModule {
FocusTransitionObserver focusTransitionObserver,
DesktopModeEventLogger desktopModeEventLogger,
DesktopModeUiEventLogger desktopModeUiEventLogger,
- DesktopTilingDecorViewModel desktopTilingDecorViewModel,
DesktopWallpaperActivityTokenProvider desktopWallpaperActivityTokenProvider,
Optional<BubbleController> bubbleController,
OverviewToDesktopTransitionObserver overviewToDesktopTransitionObserver,
@@ -789,13 +790,13 @@ public abstract class WMShellModule {
recentsTransitionHandler,
multiInstanceHelper,
mainExecutor,
+ desktopExecutor,
desktopTasksLimiter,
recentTasksController.orElse(null),
interactionJankMonitor,
mainHandler,
desktopModeEventLogger,
desktopModeUiEventLogger,
- desktopTilingDecorViewModel,
desktopWallpaperActivityTokenProvider,
bubbleController,
overviewToDesktopTransitionObserver,
@@ -915,14 +916,15 @@ public abstract class WMShellModule {
Transitions transitions,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
@DynamicOverride DesktopUserRepositories desktopUserRepositories,
- InteractionJankMonitor interactionJankMonitor) {
+ InteractionJankMonitor interactionJankMonitor,
+ Optional<BubbleController> bubbleController) {
return ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX.isTrue()
? new SpringDragToDesktopTransitionHandler(
context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories,
- interactionJankMonitor)
+ interactionJankMonitor, bubbleController)
: new DefaultDragToDesktopTransitionHandler(
context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories,
- interactionJankMonitor);
+ interactionJankMonitor, bubbleController);
}
@WMSingleton
@@ -986,7 +988,8 @@ public abstract class WMShellModule {
DesktopModeUiEventLogger desktopModeUiEventLogger,
WindowDecorTaskResourceLoader taskResourceLoader,
RecentsTransitionHandler recentsTransitionHandler,
- DesktopModeCompatPolicy desktopModeCompatPolicy
+ DesktopModeCompatPolicy desktopModeCompatPolicy,
+ DesktopTilingDecorViewModel desktopTilingDecorViewModel
) {
if (!DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)) {
return Optional.empty();
@@ -1002,7 +1005,8 @@ public abstract class WMShellModule {
desktopTasksLimiter, appHandleEducationController, appToWebEducationController,
windowDecorCaptionHandleRepository, activityOrientationChangeHandler,
focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger,
- taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy));
+ taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy,
+ desktopTilingDecorViewModel));
}
@WMSingleton
@@ -1274,10 +1278,10 @@ public abstract class WMShellModule {
@WMSingleton
@Provides
static DesktopWindowingEducationTooltipController
- provideDesktopWindowingEducationTooltipController(
- Context context,
- AdditionalSystemViewContainer.Factory additionalSystemViewContainerFactory,
- DisplayController displayController) {
+ provideDesktopWindowingEducationTooltipController(
+ Context context,
+ AdditionalSystemViewContainer.Factory additionalSystemViewContainerFactory,
+ DisplayController displayController) {
return new DesktopWindowingEducationTooltipController(
context, additionalSystemViewContainerFactory, displayController);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index e7c76bbd91b2..f8b18f29c797 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -53,6 +53,7 @@ import com.android.wm.shell.pip2.phone.PipTransition;
import com.android.wm.shell.pip2.phone.PipTransitionState;
import com.android.wm.shell.pip2.phone.PipUiStateChangeController;
import com.android.wm.shell.shared.annotations.ShellMainThread;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
@@ -85,11 +86,13 @@ public abstract class Pip2Module {
@NonNull PipDisplayLayoutState pipDisplayLayoutState,
@NonNull PipUiStateChangeController pipUiStateChangeController,
DisplayController displayController,
+ Optional<SplitScreenController> splitScreenControllerOptional,
PipDesktopState pipDesktopState) {
return new PipTransition(context, shellInit, shellTaskOrganizer, transitions,
pipBoundsState, null, pipBoundsAlgorithm, pipTaskListener,
pipScheduler, pipStackListenerController, pipDisplayLayoutState,
- pipUiStateChangeController, displayController, pipDesktopState);
+ pipUiStateChangeController, displayController, splitScreenControllerOptional,
+ pipDesktopState);
}
@WMSingleton
@@ -140,9 +143,10 @@ public abstract class Pip2Module {
PipBoundsState pipBoundsState,
@ShellMainThread ShellExecutor mainExecutor,
PipTransitionState pipTransitionState,
+ Optional<SplitScreenController> splitScreenControllerOptional,
PipDesktopState pipDesktopState) {
return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState,
- pipDesktopState);
+ splitScreenControllerOptional, pipDesktopState);
}
@WMSingleton
@@ -174,6 +178,7 @@ public abstract class Pip2Module {
@NonNull PipScheduler pipScheduler,
@NonNull SizeSpecSource sizeSpecSource,
@NonNull PipDisplayLayoutState pipDisplayLayoutState,
+ PipDesktopState pipDesktopState,
DisplayController displayController,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
@@ -182,8 +187,8 @@ public abstract class Pip2Module {
Optional<PipPerfHintController> pipPerfHintControllerOptional) {
return new PipTouchHandler(context, shellInit, shellCommandHandler, menuPhoneController,
pipBoundsAlgorithm, pipBoundsState, pipTransitionState, pipScheduler,
- sizeSpecSource, pipDisplayLayoutState, displayController, pipMotionHelper,
- floatingContentCoordinator, pipUiEventLogger, mainExecutor,
+ sizeSpecSource, pipDisplayLayoutState, pipDesktopState, displayController,
+ pipMotionHelper, floatingContentCoordinator, pipUiEventLogger, mainExecutor,
pipPerfHintControllerOptional);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt
index 6f455df6cfec..c38558d7bde9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt
@@ -26,6 +26,7 @@ import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERN
import android.view.Display.DEFAULT_DISPLAY
import android.view.IWindowManager
import android.view.WindowManager.TRANSIT_CHANGE
+import android.window.DesktopExperienceFlags
import android.window.WindowContainerTransaction
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags
@@ -62,7 +63,7 @@ class DesktopDisplayEventHandler(
private fun onInit() {
displayController.addDisplayWindowListener(this)
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) {
desktopTasksController.onDeskRemovedListener = this
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
index c9b3ec0d3a11..1f7edb413908 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
@@ -71,9 +71,31 @@ class DesktopMixedTransitionHandler(
wct: WindowContainerTransaction?,
) = freeformTaskTransitionHandler.startWindowingModeTransition(targetWindowingMode, wct)
- /** Delegates starting minimized mode transition to [FreeformTaskTransitionHandler]. */
- override fun startMinimizedModeTransition(wct: WindowContainerTransaction?): IBinder =
- freeformTaskTransitionHandler.startMinimizedModeTransition(wct)
+ /**
+ * Starts a minimize transition for [taskId], with [isLastTask] which is true if the task going
+ * to be minimized is the last visible task.
+ */
+ override fun startMinimizedModeTransition(
+ wct: WindowContainerTransaction?,
+ taskId: Int,
+ isLastTask: Boolean,
+ ): IBinder {
+ if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX.isTrue) {
+ return freeformTaskTransitionHandler.startMinimizedModeTransition(
+ wct,
+ taskId,
+ isLastTask,
+ )
+ }
+ requireNotNull(wct)
+ return transitions
+ .startTransition(Transitions.TRANSIT_MINIMIZE, wct, /* handler= */ this)
+ .also { transition ->
+ pendingMixedTransitions.add(
+ PendingMixedTransition.Minimize(transition, taskId, isLastTask)
+ )
+ }
+ }
/** Delegates starting PiP transition to [FreeformTaskTransitionHandler]. */
override fun startPipTransition(wct: WindowContainerTransaction?): IBinder =
@@ -298,7 +320,15 @@ class DesktopMixedTransitionHandler(
finishTransaction: SurfaceControl.Transaction,
finishCallback: TransitionFinishCallback,
): Boolean {
- if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue) return false
+ val shouldAnimate =
+ if (info.type == Transitions.TRANSIT_MINIMIZE) {
+ DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX.isTrue
+ } else {
+ DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue
+ }
+ if (!shouldAnimate) {
+ return false
+ }
val minimizeChange = findTaskChange(info, pending.minimizingTask)
if (minimizeChange == null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
index 03bc42f08d59..0cc8a6a5c1a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
@@ -16,7 +16,7 @@
package com.android.wm.shell.desktopmode
-import com.android.window.flags.Flags
+import android.window.DesktopExperienceFlags
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.UNKNOWN
import com.android.wm.shell.sysui.ShellCommandHandler
import java.io.PrintWriter
@@ -56,7 +56,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
pw.println("Error: task id should be an integer")
return false
}
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
return controller.moveTaskToDefaultDeskAndActivate(taskId, transitionSource = UNKNOWN)
}
if (args.size < 3) {
@@ -95,7 +95,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
}
private fun runCreateDesk(args: Array<String>, pw: PrintWriter): Boolean {
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
pw.println("Not supported.")
return false
}
@@ -116,7 +116,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
}
private fun runActivateDesk(args: Array<String>, pw: PrintWriter): Boolean {
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
pw.println("Not supported.")
return false
}
@@ -137,7 +137,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
}
private fun runRemoveDesk(args: Array<String>, pw: PrintWriter): Boolean {
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
pw.println("Not supported.")
return false
}
@@ -158,7 +158,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
}
private fun runRemoveAllDesks(args: Array<String>, pw: PrintWriter): Boolean {
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
pw.println("Not supported.")
return false
}
@@ -167,7 +167,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
}
private fun runMoveTaskToFront(args: Array<String>, pw: PrintWriter): Boolean {
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
pw.println("Not supported.")
return false
}
@@ -188,7 +188,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
}
private fun runMoveTaskOutOfDesk(args: Array<String>, pw: PrintWriter): Boolean {
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
pw.println("Not supported.")
return false
}
@@ -204,12 +204,12 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
pw.println("Error: task id should be an integer")
return false
}
- pw.println("Not implemented.")
- return false
+ controller.moveToFullscreen(taskId, transitionSource = UNKNOWN)
+ return true
}
private fun runCanCreateDesk(args: Array<String>, pw: PrintWriter): Boolean {
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
pw.println("Not supported.")
return false
}
@@ -225,7 +225,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
}
private fun runGetActiveDeskId(args: Array<String>, pw: PrintWriter): Boolean {
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
pw.println("Not supported.")
return false
}
@@ -246,7 +246,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
}
override fun printShellCommandHelp(pw: PrintWriter, prefix: String) {
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
pw.println("$prefix moveTaskToDesk <taskId> ")
pw.println("$prefix Move a task with given id to desktop mode.")
pw.println("$prefix moveToNextDisplay <taskId> ")
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index 27aed17762ff..99f052832a51 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -18,9 +18,6 @@ package com.android.wm.shell.desktopmode;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR;
@@ -28,37 +25,27 @@ import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.Indica
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.RectEvaluator;
-import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
-import android.graphics.drawable.LayerDrawable;
-import android.util.DisplayMetrics;
import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowlessWindowManager;
-import android.view.animation.DecelerateInterpolator;
+import android.window.DesktopModeFlags;
import androidx.annotation.VisibleForTesting;
import com.android.internal.policy.SystemBarUtils;
-import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.shared.annotations.ShellDesktopThread;
+import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
@@ -115,37 +102,54 @@ public class DesktopModeVisualIndicator {
}
}
+ private final VisualIndicatorViewContainer mVisualIndicatorViewContainer;
+
private final Context mContext;
private final DisplayController mDisplayController;
- private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer;
private final ActivityManager.RunningTaskInfo mTaskInfo;
- private final SurfaceControl mTaskSurface;
- private final @Nullable BubbleDropTargetBoundsProvider mBubbleBoundsProvider;
- private SurfaceControl mLeash;
-
- private final SyncTransactionQueue mSyncQueue;
- private SurfaceControlViewHost mViewHost;
- private View mView;
private IndicatorType mCurrentType;
- private DragStartState mDragStartState;
- private boolean mIsReleased;
+ private final DragStartState mDragStartState;
- public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue,
+ public DesktopModeVisualIndicator(@ShellDesktopThread ShellExecutor desktopExecutor,
+ @ShellMainThread ShellExecutor mainExecutor,
+ SyncTransactionQueue syncQueue,
ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController,
Context context, SurfaceControl taskSurface,
RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer,
DragStartState dragStartState,
@Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
- mSyncQueue = syncQueue;
+ SurfaceControl.Builder builder = new SurfaceControl.Builder();
+ taskDisplayAreaOrganizer.attachToDisplayArea(taskInfo.displayId, builder);
+ mVisualIndicatorViewContainer = new VisualIndicatorViewContainer(
+ DesktopModeFlags.ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX.isTrue()
+ ? desktopExecutor : mainExecutor,
+ mainExecutor, builder, syncQueue, bubbleBoundsProvider);
mTaskInfo = taskInfo;
mDisplayController = displayController;
mContext = context;
- mTaskSurface = taskSurface;
- mRootTdaOrganizer = taskDisplayAreaOrganizer;
- mBubbleBoundsProvider = bubbleBoundsProvider;
mCurrentType = NO_INDICATOR;
mDragStartState = dragStartState;
+ mVisualIndicatorViewContainer.createView(
+ mContext,
+ mDisplayController.getDisplay(mTaskInfo.displayId),
+ mDisplayController.getDisplayLayout(mTaskInfo.displayId),
+ mTaskInfo,
+ taskSurface
+ );
+ }
+
+ /** Start the fade out animation, running the callback on the main thread once it is done. */
+ public void fadeOutIndicator(
+ @NonNull Runnable callback) {
+ mVisualIndicatorViewContainer.fadeOutIndicator(
+ mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType, callback
+ );
+ }
+
+ /** Release the visual indicator view and its viewhost. */
+ public void releaseVisualIndicator() {
+ mVisualIndicatorViewContainer.releaseVisualIndicator();
}
/**
@@ -202,11 +206,21 @@ public class DesktopModeVisualIndicator {
}
}
if (mDragStartState != DragStartState.DRAGGED_INTENT) {
- transitionIndicator(result);
+ mVisualIndicatorViewContainer.transitionIndicator(
+ mTaskInfo, mDisplayController, mCurrentType, result
+ );
+ mCurrentType = result;
}
return result;
}
+ /**
+ * Returns the [DragStartState] of the visual indicator.
+ */
+ DragStartState getDragStartState() {
+ return mDragStartState;
+ }
+
@VisibleForTesting
Region calculateFullscreenRegion(DisplayLayout layout, int captionHeight) {
final Region region = new Region();
@@ -283,338 +297,8 @@ public class DesktopModeVisualIndicator {
layout.width(), layout.height());
}
- /**
- * Create a fullscreen indicator with no animation
- */
- private void createView() {
- if (mIsReleased) return;
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- final Resources resources = mContext.getResources();
- final DisplayMetrics metrics = resources.getDisplayMetrics();
- final int screenWidth;
- final int screenHeight;
- if (Flags.enableBugFixesForSecondaryDisplay()) {
- final DisplayLayout displayLayout =
- mDisplayController.getDisplayLayout(mTaskInfo.displayId);
- screenWidth = displayLayout.width();
- screenHeight = displayLayout.height();
- } else {
- screenWidth = metrics.widthPixels;
- screenHeight = metrics.heightPixels;
- }
- mView = new View(mContext);
- final SurfaceControl.Builder builder = new SurfaceControl.Builder();
- mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder);
- mLeash = builder
- .setName("Desktop Mode Visual Indicator")
- .setContainerLayer()
- .setCallsite("DesktopModeVisualIndicator.createView")
- .build();
- t.show(mLeash);
- final WindowManager.LayoutParams lp =
- new WindowManager.LayoutParams(screenWidth, screenHeight, TYPE_APPLICATION,
- FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
- lp.setTitle("Desktop Mode Visual Indicator");
- lp.setTrustedOverlay();
- lp.inputFeatures |= INPUT_FEATURE_NO_INPUT_CHANNEL;
- final WindowlessWindowManager windowManager = new WindowlessWindowManager(
- mTaskInfo.configuration, mLeash,
- /* hostInputToken= */ null);
- mViewHost = new SurfaceControlViewHost(mContext,
- mDisplayController.getDisplay(mTaskInfo.displayId), windowManager,
- "DesktopModeVisualIndicator");
- mViewHost.setView(mView, lp);
- // We want this indicator to be behind the dragged task, but in front of all others.
- t.setRelativeLayer(mLeash, mTaskSurface, -1);
-
- mSyncQueue.runInSync(transaction -> {
- transaction.merge(t);
- t.close();
- });
- }
-
@VisibleForTesting
Rect getIndicatorBounds() {
- return mView.getBackground().getBounds();
- }
-
- /**
- * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards.
- */
- private void fadeInIndicator(IndicatorType type) {
- mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background);
- final VisualIndicatorAnimator animator = VisualIndicatorAnimator
- .fadeBoundsIn(mView, type,
- mDisplayController.getDisplayLayout(mTaskInfo.displayId),
- mBubbleBoundsProvider);
- animator.start();
- mCurrentType = type;
- }
-
- /**
- * Fade out indicator without fully releasing it. Animator fades it out while shrinking bounds.
- *
- * @param finishCallback called when animation ends or gets cancelled
- */
- void fadeOutIndicator(@Nullable Runnable finishCallback) {
- if (mCurrentType == NO_INDICATOR) {
- // In rare cases, fade out can be requested before the indicator has determined its
- // initial type and started animating in. In this case, no animator is needed.
- finishCallback.run();
- return;
- }
- final VisualIndicatorAnimator animator = VisualIndicatorAnimator
- .fadeBoundsOut(mView, mCurrentType,
- mDisplayController.getDisplayLayout(mTaskInfo.displayId),
- mBubbleBoundsProvider);
- animator.start();
- if (finishCallback != null) {
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finishCallback.run();
- }
- });
- }
- mCurrentType = NO_INDICATOR;
- }
-
- /**
- * Takes existing indicator and animates it to bounds reflecting a new indicator type.
- */
- private void transitionIndicator(IndicatorType newType) {
- if (mCurrentType == newType) return;
- if (mView == null) {
- createView();
- }
- if (mCurrentType == NO_INDICATOR) {
- fadeInIndicator(newType);
- } else if (newType == NO_INDICATOR) {
- fadeOutIndicator(/* finishCallback= */ null);
- } else {
- final VisualIndicatorAnimator animator = VisualIndicatorAnimator.animateIndicatorType(
- mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType,
- newType, mBubbleBoundsProvider);
- mCurrentType = newType;
- animator.start();
- }
- }
-
- /**
- * Release the indicator and its components when it is no longer needed.
- */
- public void releaseVisualIndicator(SurfaceControl.Transaction t) {
- mIsReleased = true;
- if (mViewHost == null) return;
- if (mViewHost != null) {
- mViewHost.release();
- mViewHost = null;
- }
-
- if (mLeash != null) {
- t.remove(mLeash);
- mLeash = null;
- }
- }
-
- /**
- * Animator for Desktop Mode transitions which supports bounds and alpha animation.
- */
- private static class VisualIndicatorAnimator extends ValueAnimator {
- private static final int FULLSCREEN_INDICATOR_DURATION = 200;
- private static final float FULLSCREEN_SCALE_ADJUSTMENT_PERCENT = 0.015f;
- private static final float INDICATOR_FINAL_OPACITY = 0.35f;
- private static final int MAXIMUM_OPACITY = 255;
-
- /**
- * Determines how this animator will interact with the view's alpha:
- * Fade in, fade out, or no change to alpha
- */
- private enum AlphaAnimType {
- ALPHA_FADE_IN_ANIM, ALPHA_FADE_OUT_ANIM, ALPHA_NO_CHANGE_ANIM
- }
-
- private final View mView;
- private final Rect mStartBounds;
- private final Rect mEndBounds;
- private final RectEvaluator mRectEvaluator;
-
- private VisualIndicatorAnimator(View view, Rect startBounds,
- Rect endBounds) {
- mView = view;
- mStartBounds = new Rect(startBounds);
- mEndBounds = endBounds;
- setFloatValues(0, 1);
- mRectEvaluator = new RectEvaluator(new Rect());
- }
-
- private static VisualIndicatorAnimator fadeBoundsIn(
- @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout,
- @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
- final Rect endBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider);
- final Rect startBounds = getMinBounds(endBounds);
- view.getBackground().setBounds(startBounds);
-
- final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
- view, startBounds, endBounds);
- animator.setInterpolator(new DecelerateInterpolator());
- setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_IN_ANIM);
- return animator;
- }
-
- private static VisualIndicatorAnimator fadeBoundsOut(
- @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout,
- @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
- final Rect startBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider);
- final Rect endBounds = getMinBounds(startBounds);
- view.getBackground().setBounds(startBounds);
-
- final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
- view, startBounds, endBounds);
- animator.setInterpolator(new DecelerateInterpolator());
- setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_OUT_ANIM);
- return animator;
- }
-
- /**
- * Create animator for visual indicator changing type (i.e., fullscreen to freeform,
- * freeform to split, etc.)
- *
- * @param view the view for this indicator
- * @param displayLayout information about the display the transitioning task is
- * currently on
- * @param origType the original indicator type
- * @param newType the new indicator type
- * @param bubbleBoundsProvider provides bounds for bubbles indicators
- */
- private static VisualIndicatorAnimator animateIndicatorType(@NonNull View view,
- @NonNull DisplayLayout displayLayout, IndicatorType origType, IndicatorType newType,
- @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
- final Rect startBounds = getIndicatorBounds(displayLayout, origType,
- bubbleBoundsProvider);
- final Rect endBounds = getIndicatorBounds(displayLayout, newType, bubbleBoundsProvider);
- final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
- view, startBounds, endBounds);
- animator.setInterpolator(new DecelerateInterpolator());
- setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_NO_CHANGE_ANIM);
- return animator;
- }
-
- /** Calculates the bounds the indicator should have when fully faded in. */
- private static Rect getIndicatorBounds(DisplayLayout layout, IndicatorType type,
- @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
- final Rect desktopStableBounds = new Rect();
- layout.getStableBounds(desktopStableBounds);
- final int padding = desktopStableBounds.top;
- switch (type) {
- case TO_FULLSCREEN_INDICATOR:
- desktopStableBounds.top += padding;
- desktopStableBounds.bottom -= padding;
- desktopStableBounds.left += padding;
- desktopStableBounds.right -= padding;
- return desktopStableBounds;
- case TO_DESKTOP_INDICATOR:
- final float adjustmentPercentage = 1f
- - DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE;
- return new Rect((int) (adjustmentPercentage * desktopStableBounds.width() / 2),
- (int) (adjustmentPercentage * desktopStableBounds.height() / 2),
- (int) (desktopStableBounds.width()
- - (adjustmentPercentage * desktopStableBounds.width() / 2)),
- (int) (desktopStableBounds.height()
- - (adjustmentPercentage * desktopStableBounds.height() / 2)));
- case TO_SPLIT_LEFT_INDICATOR:
- return new Rect(padding, padding,
- desktopStableBounds.width() / 2 - padding,
- desktopStableBounds.height());
- case TO_SPLIT_RIGHT_INDICATOR:
- return new Rect(desktopStableBounds.width() / 2 + padding, padding,
- desktopStableBounds.width() - padding,
- desktopStableBounds.height());
- case TO_BUBBLE_LEFT_INDICATOR:
- if (bubbleBoundsProvider == null) {
- return new Rect();
- }
- return bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(
- /* onLeft= */ true);
- case TO_BUBBLE_RIGHT_INDICATOR:
- if (bubbleBoundsProvider == null) {
- return new Rect();
- }
- return bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(
- /* onLeft= */ false);
- default:
- throw new IllegalArgumentException("Invalid indicator type provided.");
- }
- }
-
- /**
- * Add necessary listener for animation of indicator
- */
- private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator,
- AlphaAnimType animType) {
- animator.addUpdateListener(a -> {
- if (animator.mView != null) {
- animator.updateBounds(a.getAnimatedFraction(), animator.mView);
- if (animType == AlphaAnimType.ALPHA_FADE_IN_ANIM) {
- animator.updateIndicatorAlpha(a.getAnimatedFraction(), animator.mView);
- } else if (animType == AlphaAnimType.ALPHA_FADE_OUT_ANIM) {
- animator.updateIndicatorAlpha(1 - a.getAnimatedFraction(), animator.mView);
- }
- } else {
- animator.cancel();
- }
- });
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- animator.mView.getBackground().setBounds(animator.mEndBounds);
- }
- });
- animator.setDuration(FULLSCREEN_INDICATOR_DURATION);
- }
-
- /**
- * Update bounds of view based on current animation fraction.
- * Use of delta is to animate bounds independently, in case we need to
- * run multiple animations simultaneously.
- *
- * @param fraction fraction to use, compared against previous fraction
- * @param view the view to update
- */
- private void updateBounds(float fraction, View view) {
- if (mStartBounds.equals(mEndBounds)) {
- return;
- }
- final Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds);
- view.getBackground().setBounds(currentBounds);
- }
-
- /**
- * Fade in the fullscreen indicator
- *
- * @param fraction current animation fraction
- */
- private void updateIndicatorAlpha(float fraction, View view) {
- final LayerDrawable drawable = (LayerDrawable) view.getBackground();
- drawable.findDrawableByLayerId(R.id.indicator_stroke)
- .setAlpha((int) (MAXIMUM_OPACITY * fraction));
- drawable.findDrawableByLayerId(R.id.indicator_solid)
- .setAlpha((int) (MAXIMUM_OPACITY * fraction * INDICATOR_FINAL_OPACITY));
- }
-
- /**
- * Return the minimum bounds of a visual indicator, to be used at the end of fading out
- * and the start of fading in.
- */
- private static Rect getMinBounds(Rect maxBounds) {
- return new Rect((int) (maxBounds.left
- + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width())),
- (int) (maxBounds.top
- + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height())),
- (int) (maxBounds.right
- - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width())),
- (int) (maxBounds.bottom
- - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height())));
- }
+ return mVisualIndicatorViewContainer.getIndicatorBounds();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 4777e7f93bc9..eba1be517147 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -22,6 +22,7 @@ import android.util.ArrayMap
import android.util.ArraySet
import android.util.SparseArray
import android.view.Display.INVALID_DISPLAY
+import android.window.DesktopExperienceFlags
import android.window.DesktopModeFlags
import androidx.core.util.forEach
import androidx.core.util.valueIterator
@@ -137,7 +138,7 @@ class DesktopRepository(
private var desktopGestureExclusionExecutor: Executor? = null
private val desktopData: DesktopData =
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
MultiDesktopData()
} else {
SingleDesktopData()
@@ -226,10 +227,19 @@ class DesktopRepository(
desktopData.setActiveDesk(displayId = displayId, deskId = deskId)
}
+ /** Sets the given desk as inactive if it was active. */
+ fun setDeskInactive(deskId: Int) {
+ desktopData.setDeskInactive(deskId)
+ }
+
/** Returns the id of the active desk in the given display, if any. */
@VisibleForTesting
fun getActiveDeskId(displayId: Int): Int? = desktopData.getActiveDesk(displayId)?.deskId
+ /** Returns the id of the desk to which this task belongs. */
+ fun getDeskIdForTask(taskId: Int): Int? =
+ desktopData.desksSequence().find { desk -> desk.activeTasks.contains(taskId) }?.deskId
+
/**
* Adds task with [taskId] to the list of freeform tasks on [displayId]'s active desk.
*
@@ -270,20 +280,40 @@ class DesktopRepository(
@VisibleForTesting
fun removeActiveTask(taskId: Int, excludedDeskId: Int? = null) {
val affectedDisplays = mutableSetOf<Int>()
- desktopData.forAllDesks { displayId, desk ->
- if (desk.deskId != excludedDeskId && desk.activeTasks.remove(taskId)) {
- logD(
- "Removed active task=%d displayId=%d deskId=%d",
- taskId,
- displayId,
- desk.deskId,
- )
- affectedDisplays.add(displayId)
+ desktopData
+ .desksSequence()
+ .filter { desk -> desk.displayId != excludedDeskId }
+ .forEach { desk ->
+ val removed = removeActiveTaskFromDesk(desk.deskId, taskId, notifyListeners = false)
+ if (removed) {
+ logD(
+ "Removed active task=%d displayId=%d deskId=%d",
+ taskId,
+ desk.displayId,
+ desk.deskId,
+ )
+ affectedDisplays.add(desk.displayId)
+ }
}
- }
affectedDisplays.forEach { displayId -> updateActiveTasksListeners(displayId) }
}
+ private fun removeActiveTaskFromDesk(
+ deskId: Int,
+ taskId: Int,
+ notifyListeners: Boolean = true,
+ ): Boolean {
+ val desk = desktopData.getDesk(deskId) ?: return false
+ if (desk.activeTasks.remove(taskId)) {
+ logD("Removed active task=%d from deskId=%d", taskId, desk.deskId)
+ if (notifyListeners) {
+ updateActiveTasksListeners(desk.displayId)
+ }
+ return true
+ }
+ return false
+ }
+
/**
* Adds given task to the closing task list for [displayId]'s active desk.
*
@@ -322,10 +352,22 @@ class DesktopRepository(
fun isActiveTask(taskId: Int) = desksSequence().any { taskId in it.activeTasks }
+ @VisibleForTesting
+ fun isActiveTaskInDesk(taskId: Int, deskId: Int): Boolean {
+ val desk = desktopData.getDesk(deskId) ?: return false
+ return taskId in desk.activeTasks
+ }
+
fun isClosingTask(taskId: Int) = desksSequence().any { taskId in it.closingTasks }
fun isVisibleTask(taskId: Int) = desksSequence().any { taskId in it.visibleTasks }
+ @VisibleForTesting
+ fun isVisibleTaskInDesk(taskId: Int, deskId: Int): Boolean {
+ val desk = desktopData.getDesk(deskId) ?: return false
+ return taskId in desk.visibleTasks
+ }
+
fun isMinimizedTask(taskId: Int) = desksSequence().any { taskId in it.minimizedTasks }
/**
@@ -415,12 +457,19 @@ class DesktopRepository(
/** Removes task from visible tasks of all desks except [excludedDeskId]. */
private fun removeVisibleTask(taskId: Int, excludedDeskId: Int? = null) {
desktopData.forAllDesks { displayId, desk ->
- if (desk.deskId != excludedDeskId && desk.visibleTasks.remove(taskId)) {
- notifyVisibleTaskListeners(displayId, desk.visibleTasks.size)
+ if (desk.deskId != excludedDeskId) {
+ removeVisibleTaskFromDesk(deskId = desk.deskId, taskId = taskId)
}
}
}
+ private fun removeVisibleTaskFromDesk(deskId: Int, taskId: Int) {
+ val desk = desktopData.getDesk(deskId) ?: return
+ if (desk.visibleTasks.remove(taskId)) {
+ notifyVisibleTaskListeners(desk.displayId, desk.visibleTasks.size)
+ }
+ }
+
/**
* Updates visibility of a freeform task with [taskId] on [displayId] and notifies listeners.
*
@@ -576,15 +625,26 @@ class DesktopRepository(
/**
* Set whether the given task is the full-immersive task in this display's active desk.
*
- * TODO: b/389960283 - add explicit [deskId] argument.
+ * TODO: b/389960283 - consider forcing callers to use [setTaskInFullImmersiveStateInDesk] with
+ * an explicit desk id instead of using this function and defaulting to the active one.
*/
fun setTaskInFullImmersiveState(displayId: Int, taskId: Int, immersive: Boolean) {
- val desktopData = desktopData.getActiveDesk(displayId) ?: return
+ val activeDesk = desktopData.getActiveDesk(displayId) ?: return
+ setTaskInFullImmersiveStateInDesk(
+ deskId = activeDesk.deskId,
+ taskId = taskId,
+ immersive = immersive,
+ )
+ }
+
+ /** Sets whether the given task is the full-immersive task in the given desk. */
+ fun setTaskInFullImmersiveStateInDesk(deskId: Int, taskId: Int, immersive: Boolean) {
+ val desk = desktopData.getDesk(deskId) ?: return
if (immersive) {
- desktopData.fullImmersiveTaskId = taskId
+ desk.fullImmersiveTaskId = taskId
} else {
- if (desktopData.fullImmersiveTaskId == taskId) {
- desktopData.fullImmersiveTaskId = null
+ if (desk.fullImmersiveTaskId == taskId) {
+ desk.fullImmersiveTaskId = null
}
}
}
@@ -674,7 +734,8 @@ class DesktopRepository(
/**
* Minimizes the task for [taskId] and [displayId]'s active display.
*
- * TODO: b/389960283 - add explicit [deskId] argument.
+ * TODO: b/389960283 - consider forcing callers to use [minimizeTaskInDesk] with an explicit
+ * desk id instead of using this function and defaulting to the active one.
*/
fun minimizeTask(displayId: Int, taskId: Int) {
if (displayId == INVALID_DISPLAY) {
@@ -683,32 +744,41 @@ class DesktopRepository(
getDisplayIdForTask(taskId)?.let { minimizeTask(it, taskId) }
?: logW("Minimize task: No display id found for task: taskId=%d", taskId)
return
- } else {
- logD("Minimize Task: display=%d, task=%d", displayId, taskId)
- desktopData.getActiveDesk(displayId)?.minimizedTasks?.add(taskId)
- ?: logD("Minimize task: No active desk found for task: taskId=%d", taskId)
}
- updateTask(displayId, taskId, isVisible = false)
+ val deskId = desktopData.getActiveDesk(displayId)?.deskId
+ if (deskId == null) {
+ logD("Minimize task: No active desk found for task: taskId=%d", taskId)
+ return
+ }
+ minimizeTaskInDesk(displayId, deskId, taskId)
+ }
+
+ /** Minimizes the task in its desk. */
+ @VisibleForTesting
+ fun minimizeTaskInDesk(displayId: Int, deskId: Int, taskId: Int) {
+ logD("Minimize Task: displayId=%d deskId=%d, task=%d", displayId, deskId, taskId)
+ desktopData.getDesk(deskId)?.minimizedTasks?.add(taskId)
+ ?: logD("Minimize task: No active desk found for task: taskId=%d", taskId)
+ updateTaskInDesk(displayId, deskId, taskId, isVisible = false)
if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
- updatePersistentRepository(displayId)
+ updatePersistentRepositoryForDesk(deskId)
}
}
/**
* Unminimizes the task for [taskId] and [displayId].
*
- * TODO: b/389960283 - consider adding an explicit [deskId] argument.
+ * TODO: b/389960283 - consider using [unminimizeTaskFromDesk] instead.
*/
fun unminimizeTask(displayId: Int, taskId: Int) {
logD("Unminimize Task: display=%d, task=%d", displayId, taskId)
- var removed = false
- desktopData.forAllDesks(displayId) { desk ->
- if (desk.minimizedTasks.remove(taskId)) {
- removed = true
- }
- }
- if (!removed) {
- logW("Unminimize Task: display=%d, task=%d, no task data", displayId, taskId)
+ desktopData.forAllDesks(displayId) { desk -> unminimizeTaskFromDesk(desk.deskId, taskId) }
+ }
+
+ private fun unminimizeTaskFromDesk(deskId: Int, taskId: Int) {
+ logD("Unminimize Task: deskId=%d, taskId=%d", deskId, taskId)
+ if (desktopData.getDesk(deskId)?.minimizedTasks?.remove(taskId) != true) {
+ logW("Unminimize Task: deskId=%d, taskId=%d, no task data", deskId, taskId)
}
}
@@ -729,7 +799,7 @@ class DesktopRepository(
* Removes [taskId] from the respective display. If [INVALID_DISPLAY], the original display id
* will be looked up from the task id.
*
- * TODO: b/389960283 - consider adding an explicit [deskId] argument.
+ * TODO: b/389960283 - consider using [removeTaskFromDesk] instead.
*/
fun removeTask(displayId: Int, taskId: Int) {
logD("Removes freeform task: taskId=%d", taskId)
@@ -745,24 +815,33 @@ class DesktopRepository(
private fun removeTaskFromDisplay(displayId: Int, taskId: Int) {
logD("Removes freeform task: taskId=%d, displayId=%d", taskId, displayId)
desktopData.forAllDesks(displayId) { desk ->
- if (desk.freeformTasksInZOrder.remove(taskId)) {
- logD(
- "Remaining freeform tasks in desk: %d, tasks: %s",
- desk.deskId,
- desk.freeformTasksInZOrder.toDumpString(),
- )
- }
+ removeTaskFromDesk(deskId = desk.deskId, taskId = taskId)
}
+ }
+
+ /** Removes the given task from the given desk. */
+ fun removeTaskFromDesk(deskId: Int, taskId: Int) {
+ logD("removeTaskFromDesk: deskId=%d, taskId=%d", deskId, taskId)
+ // TODO: b/362720497 - consider not clearing bounds on any removal, such as when moving
+ // it between desks. It might be better to allow restoring to the previous bounds as long
+ // as they're valid (probably valid if in the same display).
boundsBeforeMaximizeByTaskId.remove(taskId)
boundsBeforeFullImmersiveByTaskId.remove(taskId)
- // Remove task from unminimized task if it is minimized.
- unminimizeTask(displayId, taskId)
+ val desk = desktopData.getDesk(deskId) ?: return
+ if (desk.freeformTasksInZOrder.remove(taskId)) {
+ logD(
+ "Remaining freeform tasks in desk: %d, tasks: %s",
+ desk.deskId,
+ desk.freeformTasksInZOrder.toDumpString(),
+ )
+ }
+ unminimizeTaskFromDesk(deskId, taskId)
// Mark task as not in immersive if it was immersive.
- setTaskInFullImmersiveState(displayId = displayId, taskId = taskId, immersive = false)
- removeActiveTask(taskId)
- removeVisibleTask(taskId)
- if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
- updatePersistentRepository(displayId)
+ setTaskInFullImmersiveStateInDesk(deskId = deskId, taskId = taskId, immersive = false)
+ removeActiveTaskFromDesk(deskId = deskId, taskId = taskId)
+ removeVisibleTaskFromDesk(deskId = deskId, taskId = taskId)
+ if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue) {
+ updatePersistentRepositoryForDesk(desk.deskId)
}
}
@@ -832,24 +911,29 @@ class DesktopRepository(
private fun updatePersistentRepository(displayId: Int) {
val desks = desktopData.desksSequence(displayId).map { desk -> desk.deepCopy() }.toList()
mainCoroutineScope.launch {
- desks.forEach { desk ->
- try {
- persistentRepository.addOrUpdateDesktop(
- // Use display id as desk id for now since only once desk per display
- // is supported.
- userId = userId,
- desktopId = desk.deskId,
- visibleTasks = desk.visibleTasks,
- minimizedTasks = desk.minimizedTasks,
- freeformTasksInZOrder = desk.freeformTasksInZOrder,
- )
- } catch (exception: Exception) {
- logE(
- "An exception occurred while updating the persistent repository \n%s",
- exception.stackTrace,
- )
- }
- }
+ desks.forEach { desk -> updatePersistentRepositoryForDesk(desk) }
+ }
+ }
+
+ private fun updatePersistentRepositoryForDesk(deskId: Int) {
+ val desk = desktopData.getDesk(deskId)?.deepCopy() ?: return
+ mainCoroutineScope.launch { updatePersistentRepositoryForDesk(desk) }
+ }
+
+ private suspend fun updatePersistentRepositoryForDesk(desk: Desk) {
+ try {
+ persistentRepository.addOrUpdateDesktop(
+ userId = userId,
+ desktopId = desk.deskId,
+ visibleTasks = desk.visibleTasks,
+ minimizedTasks = desk.minimizedTasks,
+ freeformTasksInZOrder = desk.freeformTasksInZOrder,
+ )
+ } catch (exception: Exception) {
+ logE(
+ "An exception occurred while updating the persistent repository \n%s",
+ exception.stackTrace,
+ )
}
}
@@ -866,21 +950,27 @@ class DesktopRepository(
desktopData
.desksSequence()
.groupBy { it.displayId }
- .forEach { (displayId, desks) ->
+ .map { (displayId, desks) ->
+ Triple(displayId, desktopData.getActiveDesk(displayId)?.deskId, desks)
+ }
+ .forEach { (displayId, activeDeskId, desks) ->
pw.println("${prefix}Display #$displayId:")
+ pw.println("${innerPrefix}activeDesk=$activeDeskId")
+ pw.println("${innerPrefix}desks:")
+ val desksPrefix = "$innerPrefix "
desks.forEach { desk ->
- pw.println("${innerPrefix}Desk #${desk.deskId}:")
- pw.print("$innerPrefix activeTasks=")
+ pw.println("${desksPrefix}Desk #${desk.deskId}:")
+ pw.print("$desksPrefix activeTasks=")
pw.println(desk.activeTasks.toDumpString())
- pw.print("$innerPrefix visibleTasks=")
+ pw.print("$desksPrefix visibleTasks=")
pw.println(desk.visibleTasks.toDumpString())
- pw.print("$innerPrefix freeformTasksInZOrder=")
+ pw.print("$desksPrefix freeformTasksInZOrder=")
pw.println(desk.freeformTasksInZOrder.toDumpString())
- pw.print("$innerPrefix minimizedTasks=")
+ pw.print("$desksPrefix minimizedTasks=")
pw.println(desk.minimizedTasks.toDumpString())
- pw.print("$innerPrefix fullImmersiveTaskId=")
+ pw.print("$desksPrefix fullImmersiveTaskId=")
pw.println(desk.fullImmersiveTaskId)
- pw.print("$innerPrefix topTransparentFullscreenTaskId=")
+ pw.print("$desksPrefix topTransparentFullscreenTaskId=")
pw.println(desk.topTransparentFullscreenTaskId)
}
}
@@ -910,6 +1000,9 @@ class DesktopRepository(
/** Sets the given desk as the active desk in the given display. */
fun setActiveDesk(displayId: Int, deskId: Int)
+ /** Sets the desk as inactive if it was active. */
+ fun setDeskInactive(deskId: Int)
+
/**
* Returns the default desk in the given display. Useful when the system wants to activate a
* desk but doesn't care about which one it activates (e.g. when putting a window into a
@@ -990,6 +1083,11 @@ class DesktopRepository(
// existence of visible desktop windows, among other factors.
}
+ override fun setDeskInactive(deskId: Int) {
+ // No-op, in single-desk setups, which desktop is "active" is determined by the
+ // existence of visible desktop windows, among other factors.
+ }
+
override fun getDefaultDesk(displayId: Int): Desk = getDesk(deskId = displayId)
override fun getAllActiveDesks(): Set<Desk> =
@@ -1058,6 +1156,14 @@ class DesktopRepository(
display.activeDeskId = desk.deskId
}
+ override fun setDeskInactive(deskId: Int) {
+ desktopDisplays.forEach { id, display ->
+ if (display.activeDeskId == deskId) {
+ display.activeDeskId = null
+ }
+ }
+ }
+
override fun getDefaultDesk(displayId: Int): Desk? {
val display = desktopDisplays[displayId] ?: return null
return display.orderedDesks.find { it.deskId == display.activeDeskId }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
index 4d87b2189115..e831d5eecdc2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
@@ -42,6 +42,12 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser
desktopUserRepositories.getProfile(taskInfo.userId)
if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
+ // TODO: b/394281403 - with multiple desks, it's possible to have a non-freeform task
+ // inside a desk, so this should be decoupled from windowing mode.
+ // Also, changes in/out of desks are handled by the [DesksTransitionObserver], which has
+ // more specific information about the desk involved in the transition, which might be
+ // more accurate than assuming it's always the default/active desk in the display, as this
+ // method does.
// Case 1: Freeform task is changed in Desktop Mode.
if (isFreeformTask(taskInfo)) {
if (taskInfo.isVisible) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 531304d6922a..d767a0b5bd57 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -41,6 +41,7 @@ import android.os.Handler
import android.os.IBinder
import android.os.SystemProperties
import android.os.UserHandle
+import android.util.Slog
import android.view.Display.DEFAULT_DISPLAY
import android.view.DragEvent
import android.view.MotionEvent
@@ -53,6 +54,7 @@ import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_PIP
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.widget.Toast
+import android.window.DesktopExperienceFlags
import android.window.DesktopModeFlags
import android.window.DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE
import android.window.DesktopModeFlags.ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER
@@ -116,6 +118,7 @@ import com.android.wm.shell.recents.RecentsTransitionStateListener.RecentsTransi
import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING
import com.android.wm.shell.shared.TransitionUtil
import com.android.wm.shell.shared.annotations.ExternalThread
+import com.android.wm.shell.shared.annotations.ShellDesktopThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
@@ -135,7 +138,6 @@ import com.android.wm.shell.sysui.UserChangeListener
import com.android.wm.shell.transition.OneShotRemoteHandler
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TransitionFinishCallback
-import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
import com.android.wm.shell.windowdecor.DragPositioningCallbackUtility
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
import com.android.wm.shell.windowdecor.OnTaskRepositionAnimationListener
@@ -143,7 +145,7 @@ import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener
import com.android.wm.shell.windowdecor.extension.isFullscreen
import com.android.wm.shell.windowdecor.extension.isMultiWindow
import com.android.wm.shell.windowdecor.extension.requestingImmersive
-import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel
+import com.android.wm.shell.windowdecor.tiling.SnapEventHandler
import java.io.PrintWriter
import java.util.Optional
import java.util.concurrent.Executor
@@ -151,6 +153,16 @@ import java.util.concurrent.TimeUnit
import java.util.function.Consumer
import kotlin.jvm.optionals.getOrNull
+/**
+ * A callback to be invoked when a transition is started via |Transitions.startTransition| with the
+ * transition binder token that it produces.
+ *
+ * Useful when multiple components are appending WCT operations to a single transition that is
+ * started outside of their control, and each of them wants to track the transition lifecycle
+ * independently by cross-referencing the transition token with future ready-transitions.
+ */
+typealias RunOnTransitStart = (IBinder) -> Unit
+
/** Handles moving tasks in and out of desktop */
class DesktopTasksController(
private val context: Context,
@@ -176,13 +188,13 @@ class DesktopTasksController(
private val recentsTransitionHandler: RecentsTransitionHandler,
private val multiInstanceHelper: MultiInstanceHelper,
@ShellMainThread private val mainExecutor: ShellExecutor,
+ @ShellDesktopThread private val desktopExecutor: ShellExecutor,
private val desktopTasksLimiter: Optional<DesktopTasksLimiter>,
private val recentTasksController: RecentTasksController?,
private val interactionJankMonitor: InteractionJankMonitor,
@ShellMainThread private val handler: Handler,
private val desktopModeEventLogger: DesktopModeEventLogger,
private val desktopModeUiEventLogger: DesktopModeUiEventLogger,
- private val desktopTilingDecorViewModel: DesktopTilingDecorViewModel,
private val desktopWallpaperActivityTokenProvider: DesktopWallpaperActivityTokenProvider,
private val bubbleController: Optional<BubbleController>,
private val overviewToDesktopTransitionObserver: OverviewToDesktopTransitionObserver,
@@ -202,26 +214,21 @@ class DesktopTasksController(
private var userId: Int
private val desktopModeShellCommandHandler: DesktopModeShellCommandHandler =
DesktopModeShellCommandHandler(this)
- private val mOnAnimationFinishedCallback =
- Consumer<SurfaceControl.Transaction> { t: SurfaceControl.Transaction ->
- visualIndicator?.releaseVisualIndicator(t)
- visualIndicator = null
- }
+
+ private val mOnAnimationFinishedCallback = { releaseVisualIndicator() }
+ private lateinit var snapEventHandler: SnapEventHandler
private val dragToDesktopStateListener =
object : DragToDesktopStateListener {
- override fun onCommitToDesktopAnimationStart(tx: SurfaceControl.Transaction) {
- removeVisualIndicator(tx)
+ override fun onCommitToDesktopAnimationStart() {
+ removeVisualIndicator()
}
- override fun onCancelToDesktopAnimationEnd(tx: SurfaceControl.Transaction) {
- removeVisualIndicator(tx)
+ override fun onCancelToDesktopAnimationEnd() {
+ removeVisualIndicator()
}
- private fun removeVisualIndicator(tx: SurfaceControl.Transaction) {
- visualIndicator?.fadeOutIndicator {
- visualIndicator?.releaseVisualIndicator(tx)
- visualIndicator = null
- }
+ private fun removeVisualIndicator() {
+ visualIndicator?.fadeOutIndicator { releaseVisualIndicator() }
}
}
@@ -274,7 +281,7 @@ class DesktopTasksController(
RecentsTransitionStateListener.stateToString(state),
)
recentsTransitionState = state
- desktopTilingDecorViewModel.onOverviewAnimationStateChange(
+ snapEventHandler.onOverviewAnimationStateChange(
RecentsTransitionStateListener.isAnimating(state)
)
}
@@ -305,6 +312,11 @@ class DesktopTasksController(
dragToDesktopTransitionHandler.setSplitScreenController(controller)
}
+ /** Setter to handle snap events */
+ fun setSnapEventHandler(handler: SnapEventHandler) {
+ snapEventHandler = handler
+ }
+
/** Returns the transition type for the given remote transition. */
private fun transitionType(remoteTransition: RemoteTransition?): Int {
if (remoteTransition == null) {
@@ -428,7 +440,7 @@ class DesktopTasksController(
/** Creates a new desk in the given display. */
fun createDesk(displayId: Int) {
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
desksOrganizer.createDesk(displayId) { deskId ->
taskRepository.addDesk(displayId = displayId, deskId = deskId)
}
@@ -455,10 +467,7 @@ class DesktopTasksController(
}
// TODO(342378842): Instead of using default display, support multiple displays
val displayId = runningTask?.displayId ?: DEFAULT_DISPLAY
- val deskId =
- checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
- "Expected a default desk to exist"
- }
+ val deskId = getDefaultDeskId(displayId)
return moveTaskToDesk(
taskId = taskId,
deskId = deskId,
@@ -479,7 +488,7 @@ class DesktopTasksController(
): Boolean {
val runningTask = shellTaskOrganizer.getRunningTaskInfo(taskId)
if (runningTask != null) {
- moveRunningTaskToDesk(
+ return moveRunningTaskToDesk(
task = runningTask,
deskId = deskId,
wct = wct,
@@ -561,10 +570,10 @@ class DesktopTasksController(
transitionSource: DesktopModeTransitionSource,
remoteTransition: RemoteTransition? = null,
callback: IMoveToDesktopCallback? = null,
- ) {
+ ): Boolean {
if (desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing(task)) {
logW("Cannot enter desktop for taskId %d, ineligible top activity found", task.taskId)
- return
+ return false
}
val displayId = taskRepository.getDisplayForDesk(deskId)
logV(
@@ -607,7 +616,7 @@ class DesktopTasksController(
addPendingMinimizeTransition(transition, it, MinimizeReason.TASK_LIMIT)
}
exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
desksTransitionObserver.addPendingTransition(
DeskTransition.ActiveDeskWithTask(
token = transition,
@@ -619,6 +628,7 @@ class DesktopTasksController(
} else {
taskRepository.setActiveDesk(displayId = displayId, deskId = deskId)
}
+ return true
}
/**
@@ -635,7 +645,7 @@ class DesktopTasksController(
task: RunningTaskInfo,
): Int? {
val taskIdToMinimize =
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
// Activate the desk first.
prepareForDeskActivation(displayId, wct)
desksOrganizer.activateDesk(wct, deskId)
@@ -655,7 +665,7 @@ class DesktopTasksController(
// Bring other apps to front first.
bringDesktopAppsToFrontBeforeShowingNewTask(displayId, wct, task.taskId)
}
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
prepareMoveTaskToDesk(wct, task, deskId)
} else {
addMoveToDesktopChanges(wct, task)
@@ -702,10 +712,7 @@ class DesktopTasksController(
* [startDragToDesktop].
*/
private fun finalizeDragToDesktop(taskInfo: RunningTaskInfo) {
- val deskId =
- checkNotNull(taskRepository.getDefaultDeskId(taskInfo.displayId)) {
- "Expected a default desk to exist"
- }
+ val deskId = getDefaultDeskId(taskInfo.displayId)
ProtoLog.v(
WM_SHELL_DESKTOP_MODE,
"DesktopTasksController: finalizeDragToDesktop taskId=%d deskId=%d",
@@ -714,7 +721,7 @@ class DesktopTasksController(
)
val wct = WindowContainerTransaction()
exitSplitIfApplicable(wct, taskInfo)
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
// |moveHomeTask| is also called in |bringDesktopAppsToFrontBeforeShowingNewTask|, so
// this shouldn't be necessary at all.
if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
@@ -746,7 +753,7 @@ class DesktopTasksController(
addPendingMinimizeTransition(it, taskId, MinimizeReason.TASK_LIMIT)
}
exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
desksTransitionObserver.addPendingTransition(
DeskTransition.ActiveDeskWithTask(
token = transition,
@@ -787,22 +794,44 @@ class DesktopTasksController(
wct: WindowContainerTransaction,
displayId: Int,
taskInfo: RunningTaskInfo,
- ): ((IBinder) -> Unit)? {
+ ): ((IBinder) -> Unit) {
val taskId = taskInfo.taskId
- desktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId)
- performDesktopExitCleanupIfNeeded(taskId, displayId, wct, forceToFullscreen = false)
+ val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
+ snapEventHandler.removeTaskIfTiled(displayId, taskId)
+ val shouldExitDesktop =
+ willExitDesktop(
+ triggerTaskId = taskInfo.taskId,
+ displayId = displayId,
+ forceToFullscreen = false,
+ )
+ taskRepository.setPipShouldKeepDesktopActive(displayId, keepActive = true)
+ val desktopExitRunnable =
+ performDesktopExitCleanUp(
+ wct = wct,
+ deskId = deskId,
+ displayId = displayId,
+ willExitDesktop = shouldExitDesktop,
+ shouldEndUpAtHome = true,
+ )
+
taskRepository.addClosingTask(displayId, taskId)
taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
doesAnyTaskRequireTaskbarRounding(displayId, taskId)
)
- return desktopImmersiveController
- .exitImmersiveIfApplicable(
- wct = wct,
- taskInfo = taskInfo,
- reason = DesktopImmersiveController.ExitReason.CLOSED,
- )
- .asExit()
- ?.runOnTransitionStart
+
+ val immersiveRunnable =
+ desktopImmersiveController
+ .exitImmersiveIfApplicable(
+ wct = wct,
+ taskInfo = taskInfo,
+ reason = DesktopImmersiveController.ExitReason.CLOSED,
+ )
+ .asExit()
+ ?.runOnTransitionStart
+ return { transitionToken ->
+ immersiveRunnable?.invoke(transitionToken)
+ desktopExitRunnable?.invoke(transitionToken)
+ }
}
fun minimizeTask(taskInfo: RunningTaskInfo, minimizeReason: MinimizeReason) {
@@ -836,9 +865,20 @@ class DesktopTasksController(
private fun minimizeTaskInner(taskInfo: RunningTaskInfo, minimizeReason: MinimizeReason) {
val taskId = taskInfo.taskId
+ val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
val displayId = taskInfo.displayId
val wct = WindowContainerTransaction()
- performDesktopExitCleanupIfNeeded(taskId, displayId, wct, forceToFullscreen = false)
+
+ snapEventHandler.removeTaskIfTiled(displayId, taskId)
+ taskRepository.setPipShouldKeepDesktopActive(displayId, keepActive = true)
+ val willExitDesktop = willExitDesktop(taskId, displayId, forceToFullscreen = false)
+ val desktopExitRunnable =
+ performDesktopExitCleanUp(
+ wct = wct,
+ deskId = deskId,
+ displayId = displayId,
+ willExitDesktop = willExitDesktop,
+ )
// Notify immersive handler as it might need to exit immersive state.
val exitResult =
desktopImmersiveController.exitImmersiveIfApplicable(
@@ -848,7 +888,9 @@ class DesktopTasksController(
)
wct.reorder(taskInfo.token, false)
- val transition = freeformTaskTransitionStarter.startMinimizedModeTransition(wct)
+ val isLastTask = taskRepository.isOnlyVisibleNonClosingTask(taskId, displayId)
+ val transition: IBinder =
+ freeformTaskTransitionStarter.startMinimizedModeTransition(wct, taskId, isLastTask)
desktopTasksLimiter.ifPresent {
it.addPendingMinimizeChange(
transition = transition,
@@ -858,12 +900,13 @@ class DesktopTasksController(
)
}
exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
+ desktopExitRunnable?.invoke(transition)
}
/** Move a task with given `taskId` to fullscreen */
fun moveToFullscreen(taskId: Int, transitionSource: DesktopModeTransitionSource) {
shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task ->
- desktopTilingDecorViewModel.removeTaskIfTiled(task.displayId, taskId)
+ snapEventHandler.removeTaskIfTiled(task.displayId, taskId)
moveToFullscreenWithAnimation(task, task.positionInParent, transitionSource)
}
}
@@ -871,7 +914,7 @@ class DesktopTasksController(
/** Enter fullscreen by moving the focused freeform task in given `displayId` to fullscreen. */
fun enterFullscreen(displayId: Int, transitionSource: DesktopModeTransitionSource) {
getFocusedFreeformTask(displayId)?.let {
- desktopTilingDecorViewModel.removeTaskIfTiled(displayId, it.taskId)
+ snapEventHandler.removeTaskIfTiled(displayId, it.taskId)
moveToFullscreenWithAnimation(it, it.positionInParent, transitionSource)
}
}
@@ -905,7 +948,8 @@ class DesktopTasksController(
) {
logV("moveToFullscreenWithAnimation taskId=%d", task.taskId)
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task)
+ val willExitDesktop = willExitDesktop(task.taskId, task.displayId, forceToFullscreen = true)
+ val deactivationRunnable = addMoveToFullscreenChanges(wct, task, willExitDesktop)
// We are moving a freeform task to fullscreen, put the home task under the fullscreen task.
if (!forceEnterDesktop(task.displayId)) {
@@ -913,12 +957,14 @@ class DesktopTasksController(
wct.reorder(task.token, /* onTop= */ true)
}
- exitDesktopTaskTransitionHandler.startTransition(
- transitionSource,
- wct,
- position,
- mOnAnimationFinishedCallback,
- )
+ val transition =
+ exitDesktopTaskTransitionHandler.startTransition(
+ transitionSource,
+ wct,
+ position,
+ mOnAnimationFinishedCallback,
+ )
+ deactivationRunnable?.invoke(transition)
// handles case where we are moving to full screen without closing all DW tasks.
if (!taskRepository.isOnlyVisibleNonClosingTask(task.taskId)) {
@@ -990,7 +1036,7 @@ class DesktopTasksController(
logV("moveTaskToFront taskId=%s", taskInfo.taskId)
// If a task is tiled, another task should be brought to foreground with it so let
// tiling controller handle the request.
- if (desktopTilingDecorViewModel.moveTaskToFrontIfTiled(taskInfo)) {
+ if (snapEventHandler.moveTaskToFrontIfTiled(taskInfo)) {
return
}
val wct = WindowContainerTransaction()
@@ -1177,6 +1223,8 @@ class DesktopTasksController(
wct.reorder(task.token, /* onTop= */ true, /* includingParents= */ true)
}
+ // TODO: b/394268248 - desk needs to be deactivated when moving the last task and going
+ // home.
if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
performDesktopExitCleanupIfNeeded(
task.taskId,
@@ -1232,7 +1280,7 @@ class DesktopTasksController(
} else {
// Save current bounds so that task can be restored back to original bounds if necessary
// and toggle to the stable bounds.
- desktopTilingDecorViewModel.removeTaskIfTiled(taskInfo.displayId, taskInfo.taskId)
+ snapEventHandler.removeTaskIfTiled(taskInfo.displayId, taskInfo.taskId)
taskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, currentTaskBounds)
destinationBounds.set(calculateMaximizeBounds(displayLayout, taskInfo))
}
@@ -1358,7 +1406,6 @@ class DesktopTasksController(
position: SnapPosition,
resizeTrigger: ResizeTrigger,
inputMethod: InputMethod,
- desktopWindowDecoration: DesktopModeWindowDecoration,
) {
desktopModeEventLogger.logTaskResizingStarted(
resizeTrigger,
@@ -1380,13 +1427,7 @@ class DesktopTasksController(
)
if (DesktopModeFlags.ENABLE_TILE_RESIZING.isTrue()) {
- val isTiled =
- desktopTilingDecorViewModel.snapToHalfScreen(
- taskInfo,
- desktopWindowDecoration,
- position,
- currentDragBounds,
- )
+ val isTiled = snapEventHandler.snapToHalfScreen(taskInfo, currentDragBounds, position)
if (isTiled) {
taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(true)
}
@@ -1423,7 +1464,6 @@ class DesktopTasksController(
position: SnapPosition,
resizeTrigger: ResizeTrigger,
inputMethod: InputMethod,
- desktopModeWindowDecoration: DesktopModeWindowDecoration,
) {
if (!isSnapResizingAllowed(taskInfo)) {
Toast.makeText(
@@ -1442,7 +1482,6 @@ class DesktopTasksController(
position,
resizeTrigger,
inputMethod,
- desktopModeWindowDecoration,
)
}
@@ -1454,7 +1493,6 @@ class DesktopTasksController(
currentDragBounds: Rect,
dragStartBounds: Rect,
motionEvent: MotionEvent,
- desktopModeWindowDecoration: DesktopModeWindowDecoration,
) {
releaseVisualIndicator()
if (!isSnapResizingAllowed(taskInfo)) {
@@ -1502,7 +1540,6 @@ class DesktopTasksController(
position,
resizeTrigger,
DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent),
- desktopModeWindowDecoration,
)
}
}
@@ -1551,7 +1588,7 @@ class DesktopTasksController(
private fun prepareForDeskActivation(displayId: Int, wct: WindowContainerTransaction) {
// Move home to front, ensures that we go back home when all desktop windows are closed
val useParamDisplayId =
- Flags.enableMultipleDesktopsBackend() ||
+ DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ||
Flags.enablePerDisplayDesktopWallpaperActivity()
moveHomeTask(displayId = if (useParamDisplayId) displayId else context.displayId, wct = wct)
// Currently, we only handle the desktop on the default display really.
@@ -1734,33 +1771,59 @@ class DesktopTasksController(
}
}
- /**
- * Remove wallpaper activity if task provided is last task and wallpaper activity token is not
- * null
- */
- private fun performDesktopExitCleanupIfNeeded(
- taskId: Int,
+ private fun willExitDesktop(
+ triggerTaskId: Int,
displayId: Int,
- wct: WindowContainerTransaction,
forceToFullscreen: Boolean,
- shouldEndUpAtHome: Boolean = true,
- ) {
- taskRepository.setPipShouldKeepDesktopActive(displayId, !forceToFullscreen)
+ ): Boolean {
if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
- if (!taskRepository.isOnlyVisibleNonClosingTask(taskId, displayId)) {
- return
+ if (!taskRepository.isOnlyVisibleNonClosingTask(triggerTaskId, displayId)) {
+ return false
}
} else if (
Flags.enableDesktopWindowingPip() &&
taskRepository.isMinimizedPipPresentInDisplay(displayId) &&
!forceToFullscreen
) {
- return
+ return false
} else {
- if (!taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
- return
+ if (!taskRepository.isOnlyVisibleNonClosingTask(triggerTaskId)) {
+ return false
}
}
+ return true
+ }
+
+ private fun performDesktopExitCleanupIfNeeded(
+ taskId: Int,
+ displayId: Int,
+ wct: WindowContainerTransaction,
+ forceToFullscreen: Boolean,
+ shouldEndUpAtHome: Boolean = true,
+ ): RunOnTransitStart? {
+ taskRepository.setPipShouldKeepDesktopActive(displayId, keepActive = !forceToFullscreen)
+ if (!willExitDesktop(taskId, displayId, forceToFullscreen)) {
+ return null
+ }
+ // TODO: b/394268248 - update remaining callers to pass in a |deskId| and apply the
+ // |RunOnTransitStart| when the transition is started.
+ return performDesktopExitCleanUp(
+ wct = wct,
+ deskId = null,
+ displayId = displayId,
+ willExitDesktop = true,
+ shouldEndUpAtHome = shouldEndUpAtHome,
+ )
+ }
+
+ private fun performDesktopExitCleanUp(
+ wct: WindowContainerTransaction,
+ deskId: Int?,
+ displayId: Int,
+ willExitDesktop: Boolean,
+ shouldEndUpAtHome: Boolean = true,
+ ): RunOnTransitStart? {
+ if (!willExitDesktop) return null
desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(
FULLSCREEN_ANIMATION_DURATION
)
@@ -1770,16 +1833,12 @@ class DesktopTasksController(
// intent.
addLaunchHomePendingIntent(wct, displayId)
}
+ return prepareDeskDeactivationIfNeeded(wct, deskId)
}
fun releaseVisualIndicator() {
- val t = SurfaceControl.Transaction()
- visualIndicator?.releaseVisualIndicator(t)
+ visualIndicator?.releaseVisualIndicator()
visualIndicator = null
- syncQueue.runInSync { transaction ->
- transaction.merge(t)
- t.close()
- }
}
override fun getContext(): Context = context
@@ -1985,8 +2044,10 @@ class DesktopTasksController(
unminimizeReason = UnminimizeReason.APP_HANDLE_MENU_BUTTON,
)
} else {
- moveBackgroundTaskToDesktop(
+ val deskId = getDefaultDeskId(callingTask.displayId)
+ moveTaskToDesk(
requestedTaskId,
+ deskId,
WindowContainerTransaction(),
DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON,
)
@@ -1999,6 +2060,9 @@ class DesktopTasksController(
splitPosition,
options.toBundle(),
/* hideTaskToken= */ null,
+ if (enableFlexibleSplit())
+ splitScreenController.determineNewInstanceIndex(callingTask)
+ else SPLIT_INDEX_UNDEFINED,
)
}
}
@@ -2101,7 +2165,16 @@ class DesktopTasksController(
): WindowContainerTransaction? {
logV("DesktopTasksController: handleMidRecentsFreeformTaskLaunch")
val wct = WindowContainerTransaction()
- addMoveToFullscreenChanges(wct, task)
+ addMoveToFullscreenChanges(
+ wct = wct,
+ taskInfo = task,
+ willExitDesktop =
+ willExitDesktop(
+ triggerTaskId = task.taskId,
+ displayId = task.displayId,
+ forceToFullscreen = true,
+ ),
+ )
wct.reorder(task.token, true)
return wct
}
@@ -2125,7 +2198,16 @@ class DesktopTasksController(
// launched. We should make this task go to fullscreen instead of freeform. Note
// that this means any re-launch of a freeform window outside of desktop will be in
// fullscreen as long as default-desktop flag is disabled.
- addMoveToFullscreenChanges(wct, task)
+ addMoveToFullscreenChanges(
+ wct = wct,
+ taskInfo = task,
+ willExitDesktop =
+ willExitDesktop(
+ triggerTaskId = task.taskId,
+ displayId = task.displayId,
+ forceToFullscreen = true,
+ ),
+ )
return wct
}
bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
@@ -2175,7 +2257,7 @@ class DesktopTasksController(
return wct
}
if (!wct.isEmpty) {
- desktopTilingDecorViewModel.removeTaskIfTiled(task.displayId, task.taskId)
+ snapEventHandler.removeTaskIfTiled(task.displayId, task.taskId)
return wct
}
return null
@@ -2221,7 +2303,16 @@ class DesktopTasksController(
// changes we do for similar transitions. The task not having WINDOWING_MODE_UNDEFINED
// set when needed can interfere with future split / multi-instance transitions.
return WindowContainerTransaction().also { wct ->
- addMoveToFullscreenChanges(wct, task)
+ addMoveToFullscreenChanges(
+ wct = wct,
+ taskInfo = task,
+ willExitDesktop =
+ willExitDesktop(
+ triggerTaskId = task.taskId,
+ displayId = task.displayId,
+ forceToFullscreen = true,
+ ),
+ )
}
}
return null
@@ -2249,10 +2340,25 @@ class DesktopTasksController(
}
// Already fullscreen, no-op.
if (task.isFullscreen) return null
- return WindowContainerTransaction().also { wct -> addMoveToFullscreenChanges(wct, task) }
+ return WindowContainerTransaction().also { wct ->
+ addMoveToFullscreenChanges(
+ wct = wct,
+ taskInfo = task,
+ willExitDesktop =
+ willExitDesktop(
+ triggerTaskId = task.taskId,
+ displayId = task.displayId,
+ forceToFullscreen = true,
+ ),
+ )
+ }
}
- /** Handle task closing by removing wallpaper activity if it's the last active task */
+ /**
+ * Handle task closing by removing wallpaper activity if it's the last active task.
+ *
+ * TODO: b/394268248 - desk needs to be deactivated.
+ */
private fun handleTaskClosing(
task: RunningTaskInfo,
transition: IBinder,
@@ -2271,7 +2377,7 @@ class DesktopTasksController(
if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) {
taskRepository.addClosingTask(task.displayId, task.taskId)
- desktopTilingDecorViewModel.removeTaskIfTiled(task.displayId, task.taskId)
+ snapEventHandler.removeTaskIfTiled(task.displayId, task.taskId)
}
taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
@@ -2319,7 +2425,7 @@ class DesktopTasksController(
taskInfo: RunningTaskInfo,
deskId: Int,
) {
- if (!Flags.enableMultipleDesktopsBackend()) return
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
val displayId = taskRepository.getDisplayForDesk(deskId)
val displayLayout = displayController.getDisplayLayout(displayId) ?: return
val initialBounds = getInitialBounds(displayLayout, taskInfo, displayId)
@@ -2403,10 +2509,15 @@ class DesktopTasksController(
return bounds
}
+ /**
+ * Applies the changes needed to enter fullscreen and returns the id of the desk that needs to
+ * be deactivated.
+ */
private fun addMoveToFullscreenChanges(
wct: WindowContainerTransaction,
taskInfo: RunningTaskInfo,
- ) {
+ willExitDesktop: Boolean,
+ ): RunOnTransitStart? {
val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(taskInfo.displayId)!!
val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode
val targetWindowingMode =
@@ -2421,12 +2532,16 @@ class DesktopTasksController(
if (useDesktopOverrideDensity()) {
wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
}
-
- performDesktopExitCleanupIfNeeded(
- taskInfo.taskId,
- taskInfo.displayId,
- wct,
- forceToFullscreen = true,
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
+ wct.reparent(taskInfo.token, tdaInfo.token, /* onTop= */ true)
+ }
+ taskRepository.setPipShouldKeepDesktopActive(taskInfo.displayId, keepActive = false)
+ val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
+ return performDesktopExitCleanUp(
+ wct = wct,
+ deskId = deskId,
+ displayId = taskInfo.displayId,
+ willExitDesktop = willExitDesktop,
shouldEndUpAtHome = false,
)
}
@@ -2451,6 +2566,8 @@ class DesktopTasksController(
/**
* Adds split screen changes to a transaction. Note that bounds are not reset here due to
* animation; see {@link onDesktopSplitSelectAnimComplete}
+ *
+ * TODO: b/394268248 - desk needs to be deactivated.
*/
private fun addMoveToSplitChanges(wct: WindowContainerTransaction, taskInfo: RunningTaskInfo) {
// This windowing mode is to get the transition animation started; once we complete
@@ -2540,10 +2657,7 @@ class DesktopTasksController(
displayId: Int,
remoteTransition: RemoteTransition? = null,
) {
- val deskId =
- checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
- "Expected a default desk to exist"
- }
+ val deskId = getDefaultDeskId(displayId)
activateDesk(deskId, remoteTransition)
}
@@ -2551,7 +2665,7 @@ class DesktopTasksController(
fun activateDesk(deskId: Int, remoteTransition: RemoteTransition? = null) {
val displayId = taskRepository.getDisplayForDesk(deskId)
val wct = WindowContainerTransaction()
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
prepareForDeskActivation(displayId, wct)
desksOrganizer.activateDesk(wct, deskId)
if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
@@ -2572,7 +2686,7 @@ class DesktopTasksController(
val transition = transitions.startTransition(transitionType, wct, handler)
handler?.setTransition(transition)
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
desksTransitionObserver.addPendingTransition(
DeskTransition.ActivateDesk(
token = transition,
@@ -2587,16 +2701,35 @@ class DesktopTasksController(
)
}
+ /**
+ * TODO: b/393978539 - Deactivation should not happen in desktop-first devices when going home.
+ */
+ private fun prepareDeskDeactivationIfNeeded(
+ wct: WindowContainerTransaction,
+ deskId: Int?,
+ ): RunOnTransitStart? {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return null
+ if (deskId == null) return null
+ desksOrganizer.deactivateDesk(wct, deskId)
+ return { transition ->
+ desksTransitionObserver.addPendingTransition(
+ DeskTransition.DeactivateDesk(token = transition, deskId = deskId)
+ )
+ }
+ }
+
/** Removes the default desk in the given display. */
@Deprecated("Deprecated with multi-desks.", ReplaceWith("removeDesk()"))
fun removeDefaultDeskInDisplay(displayId: Int) {
- val deskId =
- checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
- "Expected a default desk to exist"
- }
+ val deskId = getDefaultDeskId(displayId)
removeDesk(displayId = displayId, deskId = deskId)
}
+ private fun getDefaultDeskId(displayId: Int) =
+ checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
+ "Expected a default desk to exist in display: $displayId"
+ }
+
/** Removes the given desk. */
fun removeDesk(deskId: Int) {
val displayId = taskRepository.getDisplayForDesk(deskId)
@@ -2608,7 +2741,7 @@ class DesktopTasksController(
logV("removeDesk deskId=%d from displayId=%d", deskId, displayId)
val tasksToRemove =
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
taskRepository.getActiveTaskIdsInDesk(deskId)
} else {
// TODO: 362720497 - make sure minimized windows are also removed in WM
@@ -2617,7 +2750,7 @@ class DesktopTasksController(
}
val wct = WindowContainerTransaction()
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
tasksToRemove.forEach {
val task = shellTaskOrganizer.getRunningTaskInfo(it)
if (task != null) {
@@ -2630,9 +2763,9 @@ class DesktopTasksController(
// TODO: 362720497 - double check background tasks are also removed.
desksOrganizer.removeDesk(wct, deskId)
}
- if (!Flags.enableMultipleDesktopsBackend() && wct.isEmpty) return
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue && wct.isEmpty) return
val transition = transitions.startTransition(TRANSIT_CLOSE, wct, /* handler= */ null)
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
desksTransitionObserver.addPendingTransition(
DeskTransition.RemoveDesk(
token = transition,
@@ -2689,15 +2822,22 @@ class DesktopTasksController(
}
/** Requests a task be transitioned from whatever mode it's in to a bubble. */
- fun requestFloat(taskInfo: RunningTaskInfo) {
+ @JvmOverloads
+ fun requestFloat(taskInfo: RunningTaskInfo, left: Boolean? = null) {
val isDragging = dragToDesktopTransitionHandler.inProgress
val shouldRequestFloat =
taskInfo.isFullscreen || taskInfo.isFreeform || isDragging || taskInfo.isMultiWindow
if (!shouldRequestFloat) return
if (isDragging) {
releaseVisualIndicator()
+ val cancelState =
+ if (left == true) DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_LEFT
+ else DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_RIGHT
+ dragToDesktopTransitionHandler.cancelDragToDesktopTransition(cancelState)
} else {
- bubbleController.ifPresent { it.expandStackAndSelectBubble(taskInfo) }
+ bubbleController.ifPresent {
+ it.expandStackAndSelectBubble(taskInfo, /* dragData= */ null)
+ }
}
}
@@ -2729,7 +2869,7 @@ class DesktopTasksController(
taskBounds: Rect,
) {
if (taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) return
- desktopTilingDecorViewModel.removeTaskIfTiled(taskInfo.displayId, taskInfo.taskId)
+ snapEventHandler.removeTaskIfTiled(taskInfo.displayId, taskInfo.taskId)
updateVisualIndicator(
taskInfo,
taskSurface,
@@ -2746,10 +2886,18 @@ class DesktopTasksController(
taskTop: Float,
dragStartState: DragStartState,
): DesktopModeVisualIndicator.IndicatorType {
+ // If the visual indicator has the wrong start state, it was never cleared from a previous
+ // drag event and needs to be cleared
+ if (visualIndicator != null && visualIndicator?.dragStartState != dragStartState) {
+ Slog.e(TAG, "Visual indicator from previous motion event was never released")
+ releaseVisualIndicator()
+ }
// If the visual indicator does not exist, create it.
val indicator =
visualIndicator
?: DesktopModeVisualIndicator(
+ desktopExecutor,
+ mainExecutor,
syncQueue,
taskInfo,
displayController,
@@ -2787,7 +2935,6 @@ class DesktopTasksController(
validDragArea: Rect,
dragStartBounds: Rect,
motionEvent: MotionEvent,
- desktopModeWindowDecoration: DesktopModeWindowDecoration,
) {
if (taskInfo.configuration.windowConfiguration.windowingMode != WINDOWING_MODE_FREEFORM) {
return
@@ -2826,7 +2973,6 @@ class DesktopTasksController(
currentDragBounds,
dragStartBounds,
motionEvent,
- desktopModeWindowDecoration,
)
}
IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
@@ -2841,7 +2987,6 @@ class DesktopTasksController(
currentDragBounds,
dragStartBounds,
motionEvent,
- desktopModeWindowDecoration,
)
}
IndicatorType.NO_INDICATOR,
@@ -2975,10 +3120,11 @@ class DesktopTasksController(
)
requestSplit(taskInfo, leftOrTop = false)
}
- IndicatorType.TO_BUBBLE_LEFT_INDICATOR,
+ IndicatorType.TO_BUBBLE_LEFT_INDICATOR -> {
+ requestFloat(taskInfo, left = true)
+ }
IndicatorType.TO_BUBBLE_RIGHT_INDICATOR -> {
- // TODO(b/388851898): move to bubble
- cancelDragToDesktop(taskInfo)
+ requestFloat(taskInfo, left = false)
}
}
return indicatorType
@@ -3126,7 +3272,7 @@ class DesktopTasksController(
logV("onUserChanged previousUserId=%d, newUserId=%d", userId, newUserId)
userId = newUserId
taskRepository = userRepositories.getProfile(userId)
- desktopTilingDecorViewModel.onUserChange()
+ snapEventHandler.onUserChange()
}
/** Called when a task's info changes. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index 8194d3cab445..0929ae15e668 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -37,6 +37,8 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.animation.FloatProperties
+import com.android.wm.shell.bubbles.BubbleController
+import com.android.wm.shell.bubbles.BubbleTransitions
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP
@@ -49,10 +51,12 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UND
import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE
import com.android.wm.shell.transition.Transitions.TransitionHandler
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator.Companion.DRAG_FREEFORM_SCALE
import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener
+import java.util.Optional
import java.util.function.Supplier
import kotlin.math.max
@@ -72,6 +76,7 @@ sealed class DragToDesktopTransitionHandler(
private val taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
private val desktopUserRepositories: DesktopUserRepositories,
protected val interactionJankMonitor: InteractionJankMonitor,
+ private val bubbleController: Optional<BubbleController>,
protected val transactionSupplier: Supplier<SurfaceControl.Transaction>,
) : TransitionHandler {
@@ -241,6 +246,21 @@ sealed class DragToDesktopTransitionHandler(
state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null)
requestSplitFromScaledTask(splitPosition, wct)
clearState()
+ } else if (
+ state.draggedTaskChange != null &&
+ (cancelState == CancelState.CANCEL_BUBBLE_LEFT ||
+ cancelState == CancelState.CANCEL_BUBBLE_RIGHT)
+ ) {
+ if (bubbleController.isEmpty || state !is TransitionState.FromFullscreen) {
+ // TODO(b/388853233): add support for dragging split task to bubble
+ startCancelAnimation()
+ } else {
+ // Animation is handled by BubbleController
+ val wct = WindowContainerTransaction()
+ restoreWindowOrder(wct, state)
+ val onLeft = cancelState == CancelState.CANCEL_BUBBLE_LEFT
+ requestBubbleFromScaledTask(wct, onLeft)
+ }
} else {
// There's no dragged task, this can happen when the "cancel" happened too quickly
// before the "start" transition is even ready (like on a fling gesture). The
@@ -258,20 +278,25 @@ sealed class DragToDesktopTransitionHandler(
) {
val state = requireTransitionState()
val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
+ val animatedTaskBounds = getAnimatedTaskBounds()
+ requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds)
+ }
+
+ private fun getAnimatedTaskBounds(): Rect {
+ val state = requireTransitionState()
+ val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
val taskBounds = Rect(taskInfo.configuration.windowConfiguration.bounds)
val taskScale = state.dragAnimator.scale
val scaledWidth = taskBounds.width() * taskScale
val scaledHeight = taskBounds.height() * taskScale
val dragPosition = PointF(state.dragAnimator.position)
state.dragAnimator.cancelAnimator()
- val animatedTaskBounds =
- Rect(
- dragPosition.x.toInt(),
- dragPosition.y.toInt(),
- (dragPosition.x + scaledWidth).toInt(),
- (dragPosition.y + scaledHeight).toInt(),
- )
- requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds)
+ return Rect(
+ dragPosition.x.toInt(),
+ dragPosition.y.toInt(),
+ (dragPosition.x + scaledWidth).toInt(),
+ (dragPosition.y + scaledHeight).toInt(),
+ )
}
private fun requestSplitSelect(
@@ -294,6 +319,29 @@ sealed class DragToDesktopTransitionHandler(
splitScreenController.requestEnterSplitSelect(taskInfo, wct, splitPosition, taskBounds)
}
+ private fun requestBubbleFromScaledTask(wct: WindowContainerTransaction, onLeft: Boolean) {
+ // TODO(b/391928049): update density once we can drag from desktop to bubble
+ val state = requireTransitionState()
+ val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
+ val taskBounds = getAnimatedTaskBounds()
+ state.dragAnimator.cancelAnimator()
+ requestBubble(wct, taskInfo, onLeft, taskBounds)
+ }
+
+ private fun requestBubble(
+ wct: WindowContainerTransaction,
+ taskInfo: RunningTaskInfo,
+ onLeft: Boolean,
+ taskBounds: Rect = Rect(taskInfo.configuration.windowConfiguration.bounds),
+ ) {
+ val controller =
+ bubbleController.orElseThrow { IllegalStateException("BubbleController not set") }
+ controller.expandStackAndSelectBubble(
+ taskInfo,
+ BubbleTransitions.DragData(taskBounds, wct, onLeft),
+ )
+ }
+
override fun startAnimation(
transition: IBinder,
info: TransitionInfo,
@@ -446,6 +494,21 @@ sealed class DragToDesktopTransitionHandler(
state.startTransitionFinishTransaction?.apply()
state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null)
requestSplitSelect(wct, taskInfo, splitPosition)
+ } else if (
+ state.cancelState == CancelState.CANCEL_BUBBLE_LEFT ||
+ state.cancelState == CancelState.CANCEL_BUBBLE_RIGHT
+ ) {
+ if (bubbleController.isEmpty || state !is TransitionState.FromFullscreen) {
+ // TODO(b/388853233): add support for dragging split task to bubble
+ startCancelDragToDesktopTransition()
+ return true
+ }
+ val taskInfo =
+ state.draggedTaskChange?.taskInfo ?: error("Expected non-null task info.")
+ val wct = WindowContainerTransaction()
+ restoreWindowOrder(wct)
+ val onLeft = state.cancelState == CancelState.CANCEL_BUBBLE_LEFT
+ requestBubble(wct, taskInfo, onLeft)
}
return true
}
@@ -476,6 +539,13 @@ sealed class DragToDesktopTransitionHandler(
clearState()
return
}
+ // In case of bubble animation, finish the initial desktop drag animation, but keep the
+ // current animation running and have bubbles take over
+ if (info.type == TRANSIT_CONVERT_TO_BUBBLE) {
+ state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null)
+ clearState()
+ return
+ }
val isCancelTransition =
info.type == TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP &&
transition == state.cancelTransitionToken &&
@@ -582,7 +652,7 @@ sealed class DragToDesktopTransitionHandler(
startPosition.y.toInt() + unscaledStartHeight,
)
- dragToDesktopStateListener?.onCommitToDesktopAnimationStart(startTransaction)
+ dragToDesktopStateListener?.onCommitToDesktopAnimationStart()
// Accept the merge by applying the merging transaction (applied by #showResizeVeil)
// and finish callback. Show the veil and position the task at the first frame before
// starting the final animation.
@@ -713,7 +783,7 @@ sealed class DragToDesktopTransitionHandler(
addListener(
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
- dragToDesktopStateListener?.onCancelToDesktopAnimationEnd(tx)
+ dragToDesktopStateListener?.onCancelToDesktopAnimationEnd()
// Start the cancel transition to restore order.
startCancelDragToDesktopTransition()
}
@@ -806,9 +876,9 @@ sealed class DragToDesktopTransitionHandler(
)
interface DragToDesktopStateListener {
- fun onCommitToDesktopAnimationStart(tx: SurfaceControl.Transaction)
+ fun onCommitToDesktopAnimationStart()
- fun onCancelToDesktopAnimationEnd(tx: SurfaceControl.Transaction)
+ fun onCancelToDesktopAnimationEnd()
}
sealed class TransitionState {
@@ -869,6 +939,10 @@ sealed class DragToDesktopTransitionHandler(
CANCEL_SPLIT_LEFT,
/** A cancel event where the task will request to enter split on the right side. */
CANCEL_SPLIT_RIGHT,
+ /** A cancel event where the task will request to bubble on the left side. */
+ CANCEL_BUBBLE_LEFT,
+ /** A cancel event where the task will request to bubble on the right side. */
+ CANCEL_BUBBLE_RIGHT,
}
companion object {
@@ -887,6 +961,7 @@ constructor(
taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
desktopUserRepositories: DesktopUserRepositories,
interactionJankMonitor: InteractionJankMonitor,
+ bubbleController: Optional<BubbleController>,
transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier {
SurfaceControl.Transaction()
},
@@ -897,6 +972,7 @@ constructor(
taskDisplayAreaOrganizer,
desktopUserRepositories,
interactionJankMonitor,
+ bubbleController,
transactionSupplier,
) {
@@ -925,6 +1001,7 @@ constructor(
taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
desktopUserRepositories: DesktopUserRepositories,
interactionJankMonitor: InteractionJankMonitor,
+ bubbleController: Optional<BubbleController>,
transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier {
SurfaceControl.Transaction()
},
@@ -935,6 +1012,7 @@ constructor(
taskDisplayAreaOrganizer,
desktopUserRepositories,
interactionJankMonitor,
+ bubbleController,
transactionSupplier,
) {
@@ -1013,7 +1091,7 @@ constructor(
val startBoundsWithOffset =
Rect(startBounds).apply { offset(startPosition.x.toInt(), startPosition.y.toInt()) }
- dragToDesktopStateListener?.onCommitToDesktopAnimationStart(startTransaction)
+ dragToDesktopStateListener?.onCommitToDesktopAnimationStart()
// Accept the merge by applying the merging transaction (applied by #showResizeVeil)
// and finish callback. Show the veil and position the task at the first frame before
// starting the final animation.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index f7f87ed63003..95cc1e68ac11 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -50,9 +50,11 @@ import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.transition.Transitions;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function0;
+
import java.util.ArrayList;
import java.util.List;
-import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -69,7 +71,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
@ShellMainThread
private final Handler mHandler;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
- private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
+ private Function0<Unit> mOnAnimationFinishedCallback;
private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
private Point mPosition;
@@ -104,14 +106,15 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
* @param position Position of the task when transition is started
* @param onAnimationEndCallback to be called after animation
*/
- public void startTransition(@NonNull DesktopModeTransitionSource transitionSource,
+ public IBinder startTransition(@NonNull DesktopModeTransitionSource transitionSource,
@NonNull WindowContainerTransaction wct, Point position,
- Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ Function0<Unit> onAnimationEndCallback) {
mPosition = position;
mOnAnimationFinishedCallback = onAnimationEndCallback;
final IBinder token = mTransitions.startTransition(getExitTransitionType(transitionSource),
wct, this);
mPendingTransitionTokens.add(token);
+ return token;
}
@Override
@@ -192,7 +195,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
@Override
public void onAnimationEnd(Animator animation) {
if (mOnAnimationFinishedCallback != null) {
- mOnAnimationFinishedCallback.accept(finishT);
+ mOnAnimationFinishedCallback.invoke();
}
mInteractionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_EXIT_MODE);
mTransitions.getMainExecutor().execute(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt
new file mode 100644
index 000000000000..2317274dbbf0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.desktopmode
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.RectEvaluator
+import android.animation.ValueAnimator
+import android.app.ActivityManager
+import android.content.Context
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.drawable.LayerDrawable
+import android.view.Display
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import android.view.WindowlessWindowManager
+import android.view.animation.DecelerateInterpolator
+import com.android.internal.annotations.VisibleForTesting
+import com.android.window.flags.Flags
+import com.android.wm.shell.R
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType
+import com.android.wm.shell.shared.annotations.ShellDesktopThread
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider
+import com.android.wm.shell.windowdecor.WindowDecoration.SurfaceControlViewHostFactory
+
+/**
+ * Container for the view / viewhost of the indicator, ensuring it is created / animated off the
+ * main thread.
+ */
+@VisibleForTesting
+class VisualIndicatorViewContainer
+@JvmOverloads
+constructor(
+ @ShellDesktopThread private val desktopExecutor: ShellExecutor,
+ @ShellMainThread private val mainExecutor: ShellExecutor,
+ private val indicatorBuilder: SurfaceControl.Builder,
+ private val syncQueue: SyncTransactionQueue,
+ private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory =
+ object : SurfaceControlViewHostFactory {},
+ private val bubbleBoundsProvider: BubbleDropTargetBoundsProvider?,
+) {
+ @VisibleForTesting var indicatorView: View? = null
+ private var indicatorViewHost: SurfaceControlViewHost? = null
+ // Below variables and the SyncTransactionQueue are the only variables that should
+ // be accessed from shell main thread. Everything else should be used exclusively
+ // from the desktop thread.
+ private var indicatorLeash: SurfaceControl? = null
+ private var isReleased = false
+
+ /** Create a fullscreen indicator with no animation */
+ @ShellMainThread
+ fun createView(
+ context: Context,
+ display: Display,
+ layout: DisplayLayout,
+ taskInfo: ActivityManager.RunningTaskInfo,
+ taskSurface: SurfaceControl,
+ ) {
+ if (isReleased) return
+ desktopExecutor.execute {
+ val resources = context.resources
+ val metrics = resources.displayMetrics
+ val screenWidth: Int
+ val screenHeight: Int
+ if (Flags.enableBugFixesForSecondaryDisplay()) {
+ screenWidth = layout.width()
+ screenHeight = layout.height()
+ } else {
+ screenWidth = metrics.widthPixels
+ screenHeight = metrics.heightPixels
+ }
+ indicatorView = View(context)
+ val leash =
+ indicatorBuilder
+ .setName("Desktop Mode Visual Indicator")
+ .setContainerLayer()
+ .setCallsite("DesktopModeVisualIndicator.createView")
+ .build()
+ val lp =
+ WindowManager.LayoutParams(
+ screenWidth,
+ screenHeight,
+ WindowManager.LayoutParams.TYPE_APPLICATION,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSPARENT,
+ )
+ lp.title = "Desktop Mode Visual Indicator"
+ lp.setTrustedOverlay()
+ lp.inputFeatures =
+ lp.inputFeatures or WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL
+ val windowManager =
+ WindowlessWindowManager(
+ taskInfo.configuration,
+ leash,
+ /* hostInputTransferToken= */ null,
+ )
+ indicatorViewHost =
+ surfaceControlViewHostFactory.create(
+ context,
+ display,
+ windowManager,
+ "VisualIndicatorViewContainer",
+ )
+ indicatorView?.let { indicatorViewHost?.setView(it, lp) }
+ showIndicator(taskSurface, leash)
+ }
+ }
+
+ private fun showIndicator(taskSurface: SurfaceControl, leash: SurfaceControl) {
+ mainExecutor.execute {
+ indicatorLeash = leash
+ val t = SurfaceControl.Transaction()
+ t.show(indicatorLeash)
+ // We want this indicator to be behind the dragged task, but in front of all others.
+ t.setRelativeLayer(indicatorLeash, taskSurface, -1)
+ syncQueue.runInSync { transaction: SurfaceControl.Transaction ->
+ transaction.merge(t)
+ t.close()
+ }
+ }
+ }
+
+ @VisibleForTesting
+ fun getIndicatorBounds(): Rect {
+ return indicatorView?.background?.getBounds() ?: Rect()
+ }
+
+ /**
+ * Takes existing indicator and animates it to bounds reflecting a new indicator type. Should
+ * only be called from the main thread.
+ */
+ @ShellMainThread
+ fun transitionIndicator(
+ taskInfo: ActivityManager.RunningTaskInfo,
+ displayController: DisplayController,
+ currentType: IndicatorType,
+ newType: IndicatorType,
+ ) {
+ if (currentType == newType || isReleased) return
+ desktopExecutor.execute {
+ val layout =
+ displayController.getDisplayLayout(taskInfo.displayId)
+ ?: error("Expected to find DisplayLayout for taskId${taskInfo.taskId}.")
+ if (currentType == IndicatorType.NO_INDICATOR) {
+ fadeInIndicator(layout, newType)
+ } else if (newType == IndicatorType.NO_INDICATOR) {
+ fadeOutIndicator(layout, currentType, /* finishCallback= */ null)
+ } else {
+ val animStartType = IndicatorType.valueOf(currentType.name)
+ val animator =
+ indicatorView?.let {
+ VisualIndicatorAnimator.animateIndicatorType(
+ it,
+ layout,
+ animStartType,
+ newType,
+ bubbleBoundsProvider,
+ )
+ } ?: return@execute
+ animator.start()
+ }
+ }
+ }
+
+ /**
+ * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards.
+ */
+ @VisibleForTesting
+ fun fadeInIndicator(layout: DisplayLayout, type: IndicatorType) {
+ desktopExecutor.assertCurrentThread()
+ indicatorView?.let {
+ it.setBackgroundResource(R.drawable.desktop_windowing_transition_background)
+ val animator =
+ VisualIndicatorAnimator.fadeBoundsIn(it, type, layout, bubbleBoundsProvider)
+ animator.start()
+ }
+ }
+
+ /**
+ * Fade out indicator without fully releasing it. Animator fades it out while shrinking bounds.
+ *
+ * @param finishCallback called when animation ends or gets cancelled
+ */
+ fun fadeOutIndicator(
+ layout: DisplayLayout,
+ currentType: IndicatorType,
+ finishCallback: Runnable?,
+ ) {
+ if (currentType == IndicatorType.NO_INDICATOR) {
+ // In rare cases, fade out can be requested before the indicator has determined its
+ // initial type and started animating in. In this case, no animator is needed.
+ finishCallback?.run()
+ return
+ }
+ desktopExecutor.execute {
+ indicatorView?.let {
+ val animStartType = IndicatorType.valueOf(currentType.name)
+ val animator =
+ VisualIndicatorAnimator.fadeBoundsOut(
+ it,
+ animStartType,
+ layout,
+ bubbleBoundsProvider,
+ )
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ if (finishCallback != null) {
+ mainExecutor.execute(finishCallback)
+ }
+ }
+ }
+ )
+ animator.start()
+ }
+ }
+ }
+
+ /** Release the indicator and its components when it is no longer needed. */
+ @ShellMainThread
+ fun releaseVisualIndicator() {
+ if (isReleased) return
+ desktopExecutor.execute {
+ indicatorViewHost?.release()
+ indicatorViewHost = null
+ }
+ indicatorLeash?.let {
+ val tx = SurfaceControl.Transaction()
+ tx.remove(it)
+ indicatorLeash = null
+ syncQueue.runInSync { transaction: SurfaceControl.Transaction ->
+ transaction.merge(tx)
+ tx.close()
+ }
+ }
+ isReleased = true
+ }
+
+ /**
+ * Animator for Desktop Mode transitions which supports bounds and alpha animation. Functions
+ * should only be called from the desktop executor.
+ */
+ @VisibleForTesting
+ class VisualIndicatorAnimator(view: View, startBounds: Rect, endBounds: Rect) :
+ ValueAnimator() {
+ /**
+ * Determines how this animator will interact with the view's alpha: Fade in, fade out, or
+ * no change to alpha
+ */
+ private enum class AlphaAnimType {
+ ALPHA_FADE_IN_ANIM,
+ ALPHA_FADE_OUT_ANIM,
+ ALPHA_NO_CHANGE_ANIM,
+ }
+
+ private val indicatorView: View = view
+ @VisibleForTesting val indicatorStartBounds = Rect(startBounds)
+ @VisibleForTesting val indicatorEndBounds = endBounds
+ private val mRectEvaluator: RectEvaluator
+
+ init {
+ setFloatValues(0f, 1f)
+ mRectEvaluator = RectEvaluator(Rect())
+ }
+
+ /**
+ * Update bounds of view based on current animation fraction. Use of delta is to animate
+ * bounds independently, in case we need to run multiple animations simultaneously.
+ *
+ * @param fraction fraction to use, compared against previous fraction
+ * @param view the view to update
+ */
+ @ShellDesktopThread
+ private fun updateBounds(fraction: Float, view: View?) {
+ if (indicatorStartBounds == indicatorEndBounds) {
+ return
+ }
+ val currentBounds =
+ mRectEvaluator.evaluate(fraction, indicatorStartBounds, indicatorEndBounds)
+ view?.background?.bounds = currentBounds
+ }
+
+ /**
+ * Fade in the fullscreen indicator
+ *
+ * @param fraction current animation fraction
+ */
+ @ShellDesktopThread
+ private fun updateIndicatorAlpha(fraction: Float, view: View?) {
+ val drawable = view?.background as LayerDrawable
+ drawable.findDrawableByLayerId(R.id.indicator_stroke).alpha =
+ (MAXIMUM_OPACITY * fraction).toInt()
+ drawable.findDrawableByLayerId(R.id.indicator_solid).alpha =
+ (MAXIMUM_OPACITY * fraction * INDICATOR_FINAL_OPACITY).toInt()
+ }
+
+ companion object {
+ private const val FULLSCREEN_INDICATOR_DURATION = 200
+ private const val FULLSCREEN_SCALE_ADJUSTMENT_PERCENT = 0.015f
+ private const val INDICATOR_FINAL_OPACITY = 0.35f
+ private const val MAXIMUM_OPACITY = 255
+
+ @ShellDesktopThread
+ fun fadeBoundsIn(
+ view: View,
+ type: IndicatorType,
+ displayLayout: DisplayLayout,
+ bubbleBoundsProvider: BubbleDropTargetBoundsProvider?,
+ ): VisualIndicatorAnimator {
+ val endBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider)
+ val startBounds = getMinBounds(endBounds)
+ view.background.bounds = startBounds
+
+ val animator = VisualIndicatorAnimator(view, startBounds, endBounds)
+ animator.interpolator = DecelerateInterpolator()
+ setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_IN_ANIM)
+ return animator
+ }
+
+ @ShellDesktopThread
+ fun fadeBoundsOut(
+ view: View,
+ type: IndicatorType,
+ displayLayout: DisplayLayout,
+ bubbleBoundsProvider: BubbleDropTargetBoundsProvider?,
+ ): VisualIndicatorAnimator {
+ val startBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider)
+ val endBounds = getMinBounds(startBounds)
+ view.background.bounds = startBounds
+
+ val animator = VisualIndicatorAnimator(view, startBounds, endBounds)
+ animator.interpolator = DecelerateInterpolator()
+ setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_OUT_ANIM)
+ return animator
+ }
+
+ /**
+ * Create animator for visual indicator changing type (i.e., fullscreen to freeform,
+ * freeform to split, etc.)
+ *
+ * @param view the view for this indicator
+ * @param displayLayout information about the display the transitioning task is
+ * currently on
+ * @param origType the original indicator type
+ * @param newType the new indicator type
+ * @param desktopExecutor: the executor for the ShellDesktopThread; should be the only
+ * thread this function runs on
+ */
+ @ShellDesktopThread
+ fun animateIndicatorType(
+ view: View,
+ displayLayout: DisplayLayout,
+ origType: IndicatorType,
+ newType: IndicatorType,
+ bubbleBoundsProvider: BubbleDropTargetBoundsProvider?,
+ ): VisualIndicatorAnimator {
+ val startBounds = getIndicatorBounds(displayLayout, origType, bubbleBoundsProvider)
+ val endBounds = getIndicatorBounds(displayLayout, newType, bubbleBoundsProvider)
+ val animator = VisualIndicatorAnimator(view, startBounds, endBounds)
+ animator.interpolator = DecelerateInterpolator()
+ setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_NO_CHANGE_ANIM)
+ return animator
+ }
+
+ /** Calculates the bounds the indicator should have when fully faded in. */
+ private fun getIndicatorBounds(
+ layout: DisplayLayout,
+ type: IndicatorType,
+ bubbleBoundsProvider: BubbleDropTargetBoundsProvider?,
+ ): Rect {
+ val desktopStableBounds = Rect()
+ layout.getStableBounds(desktopStableBounds)
+ val padding = desktopStableBounds.top
+ when (type) {
+ IndicatorType.TO_FULLSCREEN_INDICATOR -> {
+ desktopStableBounds.top += padding
+ desktopStableBounds.bottom -= padding
+ desktopStableBounds.left += padding
+ desktopStableBounds.right -= padding
+ return desktopStableBounds
+ }
+
+ IndicatorType.TO_DESKTOP_INDICATOR -> {
+ val adjustmentPercentage =
+ (1f - DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE)
+ return Rect(
+ (adjustmentPercentage * desktopStableBounds.width() / 2).toInt(),
+ (adjustmentPercentage * desktopStableBounds.height() / 2).toInt(),
+ (desktopStableBounds.width() -
+ (adjustmentPercentage * desktopStableBounds.width() / 2))
+ .toInt(),
+ (desktopStableBounds.height() -
+ (adjustmentPercentage * desktopStableBounds.height() / 2))
+ .toInt(),
+ )
+ }
+
+ IndicatorType.TO_SPLIT_LEFT_INDICATOR ->
+ return Rect(
+ padding,
+ padding,
+ desktopStableBounds.width() / 2 - padding,
+ desktopStableBounds.height(),
+ )
+
+ IndicatorType.TO_SPLIT_RIGHT_INDICATOR ->
+ return Rect(
+ desktopStableBounds.width() / 2 + padding,
+ padding,
+ desktopStableBounds.width() - padding,
+ desktopStableBounds.height(),
+ )
+ IndicatorType.TO_BUBBLE_LEFT_INDICATOR ->
+ return bubbleBoundsProvider?.getBubbleBarExpandedViewDropTargetBounds(
+ /* onLeft= */ true
+ ) ?: Rect()
+ IndicatorType.TO_BUBBLE_RIGHT_INDICATOR ->
+ return bubbleBoundsProvider?.getBubbleBarExpandedViewDropTargetBounds(
+ /* onLeft= */ false
+ ) ?: Rect()
+ else -> throw IllegalArgumentException("Invalid indicator type provided.")
+ }
+ }
+
+ /** Add necessary listener for animation of indicator */
+ private fun setupIndicatorAnimation(
+ animator: VisualIndicatorAnimator,
+ animType: AlphaAnimType,
+ ) {
+ animator.addUpdateListener { a: ValueAnimator ->
+ animator.updateBounds(a.animatedFraction, animator.indicatorView)
+ if (animType == AlphaAnimType.ALPHA_FADE_IN_ANIM) {
+ animator.updateIndicatorAlpha(a.animatedFraction, animator.indicatorView)
+ } else if (animType == AlphaAnimType.ALPHA_FADE_OUT_ANIM) {
+ animator.updateIndicatorAlpha(
+ 1 - a.animatedFraction,
+ animator.indicatorView,
+ )
+ }
+ }
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ animator.indicatorView.background.bounds = animator.indicatorEndBounds
+ }
+ }
+ )
+ animator.setDuration(FULLSCREEN_INDICATOR_DURATION.toLong())
+ }
+
+ /**
+ * Return the minimum bounds of a visual indicator, to be used at the end of fading out
+ * and the start of fading in.
+ */
+ private fun getMinBounds(maxBounds: Rect): Rect {
+ return Rect(
+ (maxBounds.left + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width()))
+ .toInt(),
+ (maxBounds.top + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height()))
+ .toInt(),
+ (maxBounds.right - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width()))
+ .toInt(),
+ (maxBounds.bottom - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height()))
+ .toInt(),
+ )
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt
index 2a8a3475c2a5..b5490cb4b595 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt
@@ -20,7 +20,7 @@ import android.util.SparseArray
import android.util.SparseBooleanArray
import android.view.Display.DEFAULT_DISPLAY
import android.window.WindowContainerToken
-import androidx.core.util.forEach
+import androidx.core.util.keyIterator
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
@@ -45,11 +45,13 @@ class DesktopWallpaperActivityTokenProvider {
}
fun removeToken(token: WindowContainerToken) {
- wallpaperActivityTokenByDisplayId.forEach { displayId, value ->
- if (value == token) {
- logV("Remove desktop wallpaper activity token for display %s", displayId)
- wallpaperActivityTokenByDisplayId.delete(displayId)
+ val displayId =
+ wallpaperActivityTokenByDisplayId.keyIterator().asSequence().find {
+ wallpaperActivityTokenByDisplayId[it] == token
}
+ if (displayId != null) {
+ logV("Remove desktop wallpaper activity token for display %s", displayId)
+ wallpaperActivityTokenByDisplayId.delete(displayId)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt
index 8c4fd9db050f..9dec96933ee5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt
@@ -42,4 +42,7 @@ sealed class DeskTransition {
val deskId: Int,
val enterTaskId: Int,
) : DeskTransition()
+
+ /** A transition to deactivate a desk. */
+ data class DeactivateDesk(override val token: IBinder, val deskId: Int) : DeskTransition()
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt
index 547890a6200a..0f2f3711a9a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt
@@ -27,6 +27,9 @@ interface DesksOrganizer {
/** Activates the given desk, making it visible in its display. */
fun activateDesk(wct: WindowContainerTransaction, deskId: Int)
+ /** Deactivates the given desk, removing it as the default launch container for new tasks. */
+ fun deactivateDesk(wct: WindowContainerTransaction, deskId: Int)
+
/** Removes the given desk and its desktop windows. */
fun removeDesk(wct: WindowContainerTransaction, deskId: Int)
@@ -37,6 +40,9 @@ interface DesksOrganizer {
task: ActivityManager.RunningTaskInfo,
)
+ /** Whether the change is for the given desk id. */
+ fun isDeskChange(change: TransitionInfo.Change, deskId: Int): Boolean
+
/**
* Returns the desk id in which the task in the given change is located at the end of a
* transition, if any.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
index 6d88c3310a63..e57b56378fb3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
@@ -17,9 +17,11 @@ package com.android.wm.shell.desktopmode.multidesks
import android.os.IBinder
import android.view.WindowManager.TRANSIT_CLOSE
+import android.window.DesktopExperienceFlags
import android.window.TransitionInfo
-import com.android.window.flags.Flags
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.desktopmode.DesktopUserRepositories
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
/**
* Observer of desk-related transitions, such as adding, removing or activating a whole desk. It
@@ -33,7 +35,7 @@ class DesksTransitionObserver(
/** Adds a pending desk transition to be tracked. */
fun addPendingTransition(transition: DeskTransition) {
- if (!Flags.enableMultipleDesktopsBackend()) return
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
deskTransitions[transition.token] = transition
}
@@ -42,8 +44,9 @@ class DesksTransitionObserver(
* observer.
*/
fun onTransitionReady(transition: IBinder, info: TransitionInfo) {
- if (!Flags.enableMultipleDesktopsBackend()) return
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
val deskTransition = deskTransitions.remove(transition) ?: return
+ logD("Desk transition ready: %s", deskTransition)
val desktopRepository = desktopUserRepositories.current
when (deskTransition) {
is DeskTransition.RemoveDesk -> {
@@ -88,6 +91,42 @@ class DesksTransitionObserver(
)
}
}
+ is DeskTransition.DeactivateDesk -> {
+ var visibleDeactivation = false
+ for (change in info.changes) {
+ val isDeskChange = desksOrganizer.isDeskChange(change, deskTransition.deskId)
+ if (isDeskChange) {
+ visibleDeactivation = true
+ continue
+ }
+ val taskId = change.taskInfo?.taskId ?: continue
+ val removedFromDesk =
+ desktopRepository.getDeskIdForTask(taskId) == deskTransition.deskId &&
+ desksOrganizer.getDeskAtEnd(change) == null
+ if (removedFromDesk) {
+ desktopRepository.removeTaskFromDesk(
+ deskId = deskTransition.deskId,
+ taskId = taskId,
+ )
+ }
+ }
+ // Always deactivate even if there's no change that confirms the desk was
+ // deactivated. Some interactions, such as the desk deactivating because it's
+ // occluded by a fullscreen task result in a transition change, but others, such
+ // as transitioning from an empty desk to home may not.
+ if (!visibleDeactivation) {
+ logD("Deactivating desk without transition change")
+ }
+ desktopRepository.setDeskInactive(deskId = deskTransition.deskId)
+ }
}
}
+
+ private fun logD(msg: String, vararg arguments: Any?) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
+
+ private companion object {
+ private const val TAG = "DesksTransitionObserver"
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt
index 5cda76e2f3e0..339932cabd2c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt
@@ -23,12 +23,12 @@ import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.util.SparseArray
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_TO_FRONT
+import android.window.DesktopExperienceFlags
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
import androidx.core.util.forEach
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.protolog.ProtoLog
-import com.android.window.flags.Flags
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer.OnCreateCallback
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
@@ -47,7 +47,7 @@ class RootTaskDesksOrganizer(
@VisibleForTesting val roots = SparseArray<DeskRoot>()
init {
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
shellInit.addInitCallback(
{ shellCommandHandler.addDumpCallback(this::dump, this) },
this,
@@ -83,6 +83,16 @@ class RootTaskDesksOrganizer(
)
}
+ override fun deactivateDesk(wct: WindowContainerTransaction, deskId: Int) {
+ logV("deactivateDesk %d", deskId)
+ val root = checkNotNull(roots[deskId]) { "Root not found for desk: $deskId" }
+ wct.setLaunchRoot(
+ /* container= */ root.taskInfo.token,
+ /* windowingModes= */ null,
+ /* activityTypes= */ null,
+ )
+ }
+
override fun moveTaskToDesk(
wct: WindowContainerTransaction,
deskId: Int,
@@ -93,6 +103,9 @@ class RootTaskDesksOrganizer(
wct.reparent(task.token, root.taskInfo.token, /* onTop= */ true)
}
+ override fun isDeskChange(change: TransitionInfo.Change, deskId: Int): Boolean =
+ roots.contains(deskId) && change.taskInfo?.taskId == deskId
+
override fun getDeskAtEnd(change: TransitionInfo.Change): Int? =
change.taskInfo?.parentTaskId?.takeIf { it in roots }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt
index 5a89451ffdbc..0507e59c06e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt
@@ -17,8 +17,8 @@
package com.android.wm.shell.desktopmode.persistence
import android.content.Context
+import android.window.DesktopExperienceFlags
import android.window.DesktopModeFlags
-import com.android.window.flags.Flags
import com.android.wm.shell.desktopmode.DesktopRepository
import com.android.wm.shell.desktopmode.DesktopUserRepositories
import com.android.wm.shell.shared.annotations.ShellMainThread
@@ -58,7 +58,7 @@ class DesktopRepositoryInitializerImpl(
repository.addDesk(
displayId = persistentDesktop.displayId,
deskId =
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
persistentDesktop.desktopId
} else {
// When disabled, desk ids are always the display id.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
index 31715f0444a9..b60fb5e7bfdd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
@@ -93,7 +93,8 @@ public class FreeformTaskTransitionHandler
}
@Override
- public IBinder startMinimizedModeTransition(WindowContainerTransaction wct) {
+ public IBinder startMinimizedModeTransition(
+ WindowContainerTransaction wct, int taskId, boolean isLastTask) {
final int type = Transitions.TRANSIT_MINIMIZE;
final IBinder token = mTransitions.startTransition(type, wct, this);
mPendingTransitionTokens.add(token);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java
index a874a5be426d..822934c1e646 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java
@@ -38,10 +38,13 @@ public interface FreeformTaskTransitionStarter {
* Starts window minimization transition
*
* @param wct the {@link WindowContainerTransaction} that changes the windowing mode
+ * @param taskId the task id of the task being minimized
+ * @param isLastTask true if the task being minimized is the last visible task
*
* @return the started transition
*/
- IBinder startMinimizedModeTransition(WindowContainerTransaction wct);
+ IBinder startMinimizedModeTransition(
+ WindowContainerTransaction wct, int taskId, boolean isLastTask);
/**
* Starts close window transition
@@ -60,4 +63,4 @@ public interface FreeformTaskTransitionStarter {
* @return the started transition
*/
IBinder startPipTransition(WindowContainerTransaction wct);
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index c0a0f469add4..d666126b91ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -22,7 +22,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.service.dreams.Flags.dismissDreamOnKeyguardDismiss;
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
-import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
@@ -201,8 +200,7 @@ public class KeyguardTransitionHandler
transition, info, startTransaction, finishTransaction, finishCallback);
}
- if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0
- || (info.getFlags() & TRANSIT_FLAG_AOD_APPEARING) != 0) {
+ if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0) {
return startAnimation(mAppearTransition, "appearing",
transition, info, startTransaction, finishTransaction, finishCallback);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index da3181096d98..cef18f55b86d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -145,7 +145,7 @@ public abstract class PipTransitionController implements Transitions.TransitionH
/**
* Called when the Shell wants to start an exit-via-expand from Pip transition/animation.
*/
- public void startExpandTransition(WindowContainerTransaction out) {
+ public void startExpandTransition(WindowContainerTransaction out, boolean toSplit) {
// Default implementation does nothing.
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java
index 71697596afd3..a837e7d308eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java
@@ -296,6 +296,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
return;
}
+ mMagneticTarget.updateLocationOnScreen();
createOrUpdateDismissTarget();
if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java
new file mode 100644
index 000000000000..bd0b810b2a44
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.pip2.phone;
+
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP;
+import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_NONE;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.view.MotionEvent;
+
+import com.android.internal.policy.TaskResizingAlgorithm;
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.common.pip.PipBoundsState;
+
+import java.util.function.Function;
+
+/** Helper for handling drag-corner-to-resize gestures. */
+public class PipDragToResizeHandler {
+ private final Context mContext;
+ private final PipResizeGestureHandler mPipResizeGestureHandler;
+ private final PipBoundsState mPipBoundsState;
+ private final PhonePipMenuController mPhonePipMenuController;
+ private final PipBoundsAlgorithm mPipBoundsAlgorithm;
+ private final PipScheduler mPipScheduler;
+
+ private final Region mTmpRegion = new Region();
+ private final Rect mDragCornerSize = new Rect();
+ private final Rect mTmpTopLeftCorner = new Rect();
+ private final Rect mTmpTopRightCorner = new Rect();
+ private final Rect mTmpBottomLeftCorner = new Rect();
+ private final Rect mTmpBottomRightCorner = new Rect();
+ private final Rect mDisplayBounds = new Rect();
+ private final Function<Rect, Rect> mMovementBoundsSupplier;
+ private int mDelta;
+
+ public PipDragToResizeHandler(Context context, PipResizeGestureHandler pipResizeGestureHandler,
+ PipBoundsState pipBoundsState,
+ PhonePipMenuController phonePipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipScheduler pipScheduler, Function<Rect, Rect> movementBoundsSupplier) {
+ mContext = context;
+ mPipResizeGestureHandler = pipResizeGestureHandler;
+ mPipBoundsState = pipBoundsState;
+ mPhonePipMenuController = phonePipMenuController;
+ mPipBoundsAlgorithm = pipBoundsAlgorithm;
+ mPipScheduler = pipScheduler;
+ mMovementBoundsSupplier = movementBoundsSupplier;
+ }
+
+ /** Invoked by {@link PipResizeGestureHandler#reloadResources}. */
+ void reloadResources() {
+ final Resources res = mContext.getResources();
+ mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size);
+ }
+
+ /** Invoked by {@link PipResizeGestureHandler#onInputEvent} if drag-corner-to-resize is
+ * enabled. */
+ void onDragCornerResize(MotionEvent ev, Rect lastResizeBounds, PointF downPoint,
+ Rect downBounds, Point minSize, Point maxSize, float touchSlop) {
+ int action = ev.getActionMasked();
+ float x = ev.getX();
+ float y = ev.getY();
+ if (action == MotionEvent.ACTION_DOWN) {
+ lastResizeBounds.setEmpty();
+ final boolean allowGesture = isWithinDragResizeRegion((int) x, (int) y);
+ mPipResizeGestureHandler.setAllowGesture(allowGesture);
+ if (allowGesture) {
+ setCtrlType((int) x, (int) y);
+ downPoint.set(x, y);
+ downBounds.set(mPipBoundsState.getBounds());
+ }
+ } else if (mPipResizeGestureHandler.getAllowGesture()) {
+ switch (action) {
+ case MotionEvent.ACTION_POINTER_DOWN:
+ // We do not support multi touch for resizing via drag
+ mPipResizeGestureHandler.setAllowGesture(false);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ final boolean thresholdCrossed = mPipResizeGestureHandler.getThresholdCrossed();
+ // Capture inputs
+ if (!mPipResizeGestureHandler.getThresholdCrossed()
+ && Math.hypot(x - downPoint.x, y - downPoint.y) > touchSlop) {
+ mPipResizeGestureHandler.setThresholdCrossed(true);
+ // Reset the down to begin resizing from this point
+ downPoint.set(x, y);
+ mPipResizeGestureHandler.pilferPointers();
+ }
+ if (mPipResizeGestureHandler.getThresholdCrossed()) {
+ if (mPhonePipMenuController.isMenuVisible()) {
+ mPhonePipMenuController.hideMenu(ANIM_TYPE_NONE,
+ false /* resize */);
+ }
+ final Rect currentPipBounds = mPipBoundsState.getBounds();
+ lastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y,
+ downPoint.x, downPoint.y, currentPipBounds,
+ mPipResizeGestureHandler.getCtrlType(), minSize.x,
+ minSize.y, maxSize, true,
+ downBounds.width() > downBounds.height()));
+ mPipBoundsAlgorithm.transformBoundsToAspectRatio(lastResizeBounds,
+ mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
+ true /* useCurrentSize */);
+ mPipScheduler.scheduleUserResizePip(lastResizeBounds);
+ mPipBoundsState.setHasUserResizedPip(true);
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mPipResizeGestureHandler.finishResize();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Check whether the current x,y coordinate is within the region in which drag-resize should
+ * start.
+ * This consists of 4 small squares on the 4 corners of the PIP window, a quarter of which
+ * overlaps with the PIP window while the rest goes outside of the PIP window.
+ * _ _ _ _
+ * |_|_|_________|_|_|
+ * |_|_| |_|_|
+ * | PIP |
+ * | WINDOW |
+ * _|_ _|_
+ * |_|_|_________|_|_|
+ * |_|_| |_|_|
+ */
+ boolean isWithinDragResizeRegion(int x, int y) {
+ final Rect currentPipBounds = mPipBoundsState.getBounds();
+ if (currentPipBounds == null) {
+ return false;
+ }
+ resetDragCorners();
+ mTmpTopLeftCorner.offset(currentPipBounds.left - mDelta / 2,
+ currentPipBounds.top - mDelta / 2);
+ mTmpTopRightCorner.offset(currentPipBounds.right - mDelta / 2,
+ currentPipBounds.top - mDelta / 2);
+ mTmpBottomLeftCorner.offset(currentPipBounds.left - mDelta / 2,
+ currentPipBounds.bottom - mDelta / 2);
+ mTmpBottomRightCorner.offset(currentPipBounds.right - mDelta / 2,
+ currentPipBounds.bottom - mDelta / 2);
+
+ mTmpRegion.setEmpty();
+ mTmpRegion.op(mTmpTopLeftCorner, Region.Op.UNION);
+ mTmpRegion.op(mTmpTopRightCorner, Region.Op.UNION);
+ mTmpRegion.op(mTmpBottomLeftCorner, Region.Op.UNION);
+ mTmpRegion.op(mTmpBottomRightCorner, Region.Op.UNION);
+
+ return mTmpRegion.contains(x, y);
+ }
+
+ private void resetDragCorners() {
+ mDragCornerSize.set(0, 0, mDelta, mDelta);
+ mTmpTopLeftCorner.set(mDragCornerSize);
+ mTmpTopRightCorner.set(mDragCornerSize);
+ mTmpBottomLeftCorner.set(mDragCornerSize);
+ mTmpBottomRightCorner.set(mDragCornerSize);
+ }
+
+ private void setCtrlType(int x, int y) {
+ final Rect currentPipBounds = mPipBoundsState.getBounds();
+ int ctrlType = mPipResizeGestureHandler.getCtrlType();
+
+ Rect movementBounds = mMovementBoundsSupplier.apply(currentPipBounds);
+
+ mDisplayBounds.set(movementBounds.left,
+ movementBounds.top,
+ movementBounds.right + currentPipBounds.width(),
+ movementBounds.bottom + currentPipBounds.height());
+
+ if (mTmpTopLeftCorner.contains(x, y) && currentPipBounds.top != mDisplayBounds.top
+ && currentPipBounds.left != mDisplayBounds.left) {
+ ctrlType |= CTRL_LEFT;
+ ctrlType |= CTRL_TOP;
+ }
+ if (mTmpTopRightCorner.contains(x, y) && currentPipBounds.top != mDisplayBounds.top
+ && currentPipBounds.right != mDisplayBounds.right) {
+ ctrlType |= CTRL_RIGHT;
+ ctrlType |= CTRL_TOP;
+ }
+ if (mTmpBottomRightCorner.contains(x, y)
+ && currentPipBounds.bottom != mDisplayBounds.bottom
+ && currentPipBounds.right != mDisplayBounds.right) {
+ ctrlType |= CTRL_RIGHT;
+ ctrlType |= CTRL_BOTTOM;
+ }
+ if (mTmpBottomLeftCorner.contains(x, y)
+ && currentPipBounds.bottom != mDisplayBounds.bottom
+ && currentPipBounds.left != mDisplayBounds.left) {
+ ctrlType |= CTRL_LEFT;
+ ctrlType |= CTRL_BOTTOM;
+ }
+
+ mPipResizeGestureHandler.setCtrlType(ctrlType);
+ }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java
new file mode 100644
index 000000000000..1e41af379864
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.pip2.phone;
+
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.MotionEvent;
+
+import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipPinchResizingAlgorithm;
+
+/** Helper for handling pinch-to-resize gestures. */
+public class PipPinchToResizeHandler {
+ private final PipResizeGestureHandler mPipResizeGestureHandler;
+ private final PipBoundsState mPipBoundsState;
+ private final PhonePipMenuController mPhonePipMenuController;
+ private final PipScheduler mPipScheduler;
+ private final PipPinchResizingAlgorithm mPinchResizingAlgorithm;
+
+ private int mFirstIndex = -1;
+ private int mSecondIndex = -1;
+
+ public PipPinchToResizeHandler(PipResizeGestureHandler pipResizeGestureHandler,
+ PipBoundsState pipBoundsState, PhonePipMenuController phonePipMenuController,
+ PipScheduler pipScheduler) {
+ mPipResizeGestureHandler = pipResizeGestureHandler;
+ mPipBoundsState = pipBoundsState;
+ mPhonePipMenuController = phonePipMenuController;
+ mPipScheduler = pipScheduler;
+
+ mPinchResizingAlgorithm = new PipPinchResizingAlgorithm();
+ }
+
+ /** Invoked by {@link PipResizeGestureHandler#onInputEvent} if pinch-to-resize is enabled. */
+ void onPinchResize(MotionEvent ev, PointF downPoint, PointF downSecondPoint, Rect downBounds,
+ PointF lastPoint, PointF lastSecondPoint, Rect lastResizeBounds, float touchSlop,
+ Point minSize, Point maxSize) {
+ int action = ev.getActionMasked();
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ mFirstIndex = -1;
+ mSecondIndex = -1;
+ mPipResizeGestureHandler.setAllowGesture(false);
+ mPipResizeGestureHandler.finishResize();
+ }
+
+ if (ev.getPointerCount() != 2) {
+ return;
+ }
+
+ final Rect pipBounds = mPipBoundsState.getBounds();
+ if (action == MotionEvent.ACTION_POINTER_DOWN) {
+ if (mFirstIndex == -1 && mSecondIndex == -1
+ && pipBounds.contains((int) ev.getRawX(0), (int) ev.getRawY(0))
+ && pipBounds.contains((int) ev.getRawX(1), (int) ev.getRawY(1))) {
+ mPipResizeGestureHandler.setAllowGesture(true);
+ mFirstIndex = 0;
+ mSecondIndex = 1;
+ downPoint.set(ev.getRawX(mFirstIndex), ev.getRawY(mFirstIndex));
+ downSecondPoint.set(ev.getRawX(mSecondIndex), ev.getRawY(mSecondIndex));
+ downBounds.set(pipBounds);
+
+ lastPoint.set(downPoint);
+ lastSecondPoint.set(lastSecondPoint);
+ lastResizeBounds.set(downBounds);
+
+ // start the high perf session as the second pointer gets detected
+ mPipResizeGestureHandler.startHighPerfSession();
+ }
+ }
+
+ if (action == MotionEvent.ACTION_MOVE) {
+ if (mFirstIndex == -1 || mSecondIndex == -1) {
+ return;
+ }
+
+ float x0 = ev.getRawX(mFirstIndex);
+ float y0 = ev.getRawY(mFirstIndex);
+ float x1 = ev.getRawX(mSecondIndex);
+ float y1 = ev.getRawY(mSecondIndex);
+ lastPoint.set(x0, y0);
+ lastSecondPoint.set(x1, y1);
+
+ // Capture inputs
+ if (!mPipResizeGestureHandler.getThresholdCrossed()
+ && (distanceBetween(downSecondPoint, lastSecondPoint) > touchSlop
+ || distanceBetween(downPoint, lastPoint) > touchSlop)) {
+ mPipResizeGestureHandler.pilferPointers();
+ mPipResizeGestureHandler.setThresholdCrossed(true);
+ // Reset the down to begin resizing from this point
+ downPoint.set(lastPoint);
+ downSecondPoint.set(lastSecondPoint);
+
+ if (mPhonePipMenuController.isMenuVisible()) {
+ mPhonePipMenuController.hideMenu();
+ }
+ }
+
+ if (mPipResizeGestureHandler.getThresholdCrossed()) {
+ final float angle = mPinchResizingAlgorithm.calculateBoundsAndAngle(downPoint,
+ downSecondPoint, lastPoint, lastSecondPoint, minSize, maxSize,
+ downBounds, lastResizeBounds);
+
+ mPipResizeGestureHandler.setAngle(angle);
+ mPipScheduler.scheduleUserResizePip(lastResizeBounds, angle);
+ mPipBoundsState.setHasUserResizedPip(true);
+ }
+ }
+ }
+
+ private float distanceBetween(PointF p1, PointF p2) {
+ return (float) Math.hypot(p2.x - p1.x, p2.y - p1.y);
+ }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
index e4be3f60f86e..b869bf153c34 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
@@ -44,13 +44,14 @@ import com.android.wm.shell.R;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipDesktopState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
import com.android.wm.shell.common.pip.PipPerfHintController;
-import com.android.wm.shell.common.pip.PipPinchResizingAlgorithm;
import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip2.animation.PipResizeAnimator;
import java.io.PrintWriter;
+import java.util.function.Function;
/**
* Helper on top of PipTouchHandler that handles inputs OUTSIDE of the PIP window, which is used to
@@ -72,8 +73,8 @@ public class PipResizeGestureHandler implements
private final PipTransitionState mPipTransitionState;
private final PhonePipMenuController mPhonePipMenuController;
private final PipDisplayLayoutState mPipDisplayLayoutState;
+ private final PipDesktopState mPipDesktopState;
private final PipUiEventLogger mPipUiEventLogger;
- private final PipPinchResizingAlgorithm mPinchResizingAlgorithm;
private final ShellExecutor mMainExecutor;
private final PointF mDownPoint = new PointF();
@@ -93,16 +94,18 @@ public class PipResizeGestureHandler implements
private boolean mIsAttached;
private boolean mIsEnabled;
private boolean mEnablePinchResize;
+ private boolean mEnableDragCornerResize;
private boolean mIsSysUiStateValid;
private boolean mThresholdCrossed;
private boolean mOngoingPinchToResize = false;
private boolean mWaitingForBoundsChangeTransition = false;
private float mAngle = 0;
- int mFirstIndex = -1;
- int mSecondIndex = -1;
+
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
+ private PipDragToResizeHandler mPipDragToResizeHandler;
+ private PipPinchToResizeHandler mPipPinchToResizeHandler;
@Nullable
private final PipPerfHintController mPipPerfHintController;
@@ -121,7 +124,9 @@ public class PipResizeGestureHandler implements
PipTransitionState pipTransitionState,
PipUiEventLogger pipUiEventLogger,
PhonePipMenuController menuActivityController,
+ Function<Rect, Rect> movementBoundsSupplier,
PipDisplayLayoutState pipDisplayLayoutState,
+ PipDesktopState pipDesktopState,
ShellExecutor mainExecutor,
@Nullable PipPerfHintController pipPerfHintController) {
mContext = context;
@@ -137,8 +142,13 @@ public class PipResizeGestureHandler implements
mPhonePipMenuController = menuActivityController;
mPipDisplayLayoutState = pipDisplayLayoutState;
+ mPipDesktopState = pipDesktopState;
mPipUiEventLogger = pipUiEventLogger;
- mPinchResizingAlgorithm = new PipPinchResizingAlgorithm();
+
+ mPipDragToResizeHandler = new PipDragToResizeHandler(context, this, pipBoundsState,
+ menuActivityController, pipBoundsAlgorithm, pipScheduler, movementBoundsSupplier);
+ mPipPinchToResizeHandler = new PipPinchToResizeHandler(this, pipBoundsState,
+ menuActivityController, pipScheduler);
}
void init() {
@@ -163,6 +173,7 @@ public class PipResizeGestureHandler implements
}
private void reloadResources() {
+ mPipDragToResizeHandler.reloadResources();
mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
}
@@ -180,6 +191,8 @@ public class PipResizeGestureHandler implements
void onActivityPinned() {
mIsAttached = true;
updateIsEnabled();
+ // Only enable drag-corner-to-resize if PiP was entered when Desktop Mode session is active.
+ mEnableDragCornerResize = mPipDesktopState.isPipInDesktopMode();
}
void onActivityUnpinned() {
@@ -211,9 +224,44 @@ public class PipResizeGestureHandler implements
}
}
+ boolean getAllowGesture() {
+ return mAllowGesture;
+ }
+
+ void setAllowGesture(boolean allowGesture) {
+ mAllowGesture = allowGesture;
+ }
+
+ boolean getThresholdCrossed() {
+ return mThresholdCrossed;
+ }
+
+ void setThresholdCrossed(boolean thresholdCrossed) {
+ mThresholdCrossed = thresholdCrossed;
+ }
+
+ int getCtrlType() {
+ return mCtrlType;
+ }
+
+ void setCtrlType(int ctrlType) {
+ mCtrlType = ctrlType;
+ }
+
+ void setAngle(float angle) {
+ mAngle = angle;
+ }
+
+ void startHighPerfSession() {
+ if (mPipPerfHintController != null) {
+ mPipHighPerfSession = mPipPerfHintController.startSession(
+ this::onHighPerfSessionTimeout, "onPinchResize");
+ }
+ }
+
@VisibleForTesting
void onInputEvent(InputEvent ev) {
- if (!mEnablePinchResize) {
+ if (!mEnableDragCornerResize && !mEnablePinchResize) {
// No need to handle anything if resizing isn't enabled.
return;
}
@@ -240,7 +288,12 @@ public class PipResizeGestureHandler implements
}
if (mOngoingPinchToResize) {
- onPinchResize(mv);
+ mPipPinchToResizeHandler.onPinchResize(mv, mDownPoint, mDownSecondPoint,
+ mDownBounds, mLastPoint, mLastSecondPoint, mLastResizeBounds, mTouchSlop,
+ mMinSize, mMaxSize);
+ } else if (mEnableDragCornerResize) {
+ mPipDragToResizeHandler.onDragCornerResize(mv, mLastResizeBounds, mDownPoint,
+ mDownBounds, mMinSize, mMaxSize, mTouchSlop);
}
}
}
@@ -261,20 +314,31 @@ public class PipResizeGestureHandler implements
}
boolean willStartResizeGesture(MotionEvent ev) {
- if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
- if (mEnablePinchResize && ev.getPointerCount() == 2) {
- onPinchResize(ev);
- mOngoingPinchToResize = mAllowGesture;
- return mAllowGesture;
- }
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ if (mEnableDragCornerResize && mPipDragToResizeHandler.isWithinDragResizeRegion(
+ (int) ev.getRawX(),
+ (int) ev.getRawY())) {
+ return true;
+ }
+ break;
+
+ case MotionEvent.ACTION_POINTER_DOWN:
+ if (mEnablePinchResize && ev.getPointerCount() == 2) {
+ mPipPinchToResizeHandler.onPinchResize(ev, mDownPoint, mDownSecondPoint,
+ mDownBounds, mLastPoint, mLastSecondPoint, mLastResizeBounds,
+ mTouchSlop, mMinSize, mMaxSize);
+ mOngoingPinchToResize = mAllowGesture;
+ return mAllowGesture;
+ }
+ break;
+
+ default:
+ break;
}
return false;
}
- private boolean isInValidSysUiState() {
- return mIsSysUiStateValid;
- }
-
private void onHighPerfSessionTimeout(PipPerfHintController.PipHighPerfSession session) {}
private void cleanUpHighPerfSessionMaybe() {
@@ -285,83 +349,6 @@ public class PipResizeGestureHandler implements
}
}
- @VisibleForTesting
- void onPinchResize(MotionEvent ev) {
- int action = ev.getActionMasked();
-
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- mFirstIndex = -1;
- mSecondIndex = -1;
- mAllowGesture = false;
- finishResize();
- }
-
- if (ev.getPointerCount() != 2) {
- return;
- }
-
- final Rect pipBounds = mPipBoundsState.getBounds();
- if (action == MotionEvent.ACTION_POINTER_DOWN) {
- if (mFirstIndex == -1 && mSecondIndex == -1
- && pipBounds.contains((int) ev.getRawX(0), (int) ev.getRawY(0))
- && pipBounds.contains((int) ev.getRawX(1), (int) ev.getRawY(1))) {
- mAllowGesture = true;
- mFirstIndex = 0;
- mSecondIndex = 1;
- mDownPoint.set(ev.getRawX(mFirstIndex), ev.getRawY(mFirstIndex));
- mDownSecondPoint.set(ev.getRawX(mSecondIndex), ev.getRawY(mSecondIndex));
- mDownBounds.set(pipBounds);
-
- mLastPoint.set(mDownPoint);
- mLastSecondPoint.set(mLastSecondPoint);
- mLastResizeBounds.set(mDownBounds);
-
- // start the high perf session as the second pointer gets detected
- if (mPipPerfHintController != null) {
- mPipHighPerfSession = mPipPerfHintController.startSession(
- this::onHighPerfSessionTimeout, "onPinchResize");
- }
- }
- }
-
- if (action == MotionEvent.ACTION_MOVE) {
- if (mFirstIndex == -1 || mSecondIndex == -1) {
- return;
- }
-
- float x0 = ev.getRawX(mFirstIndex);
- float y0 = ev.getRawY(mFirstIndex);
- float x1 = ev.getRawX(mSecondIndex);
- float y1 = ev.getRawY(mSecondIndex);
- mLastPoint.set(x0, y0);
- mLastSecondPoint.set(x1, y1);
-
- // Capture inputs
- if (!mThresholdCrossed
- && (distanceBetween(mDownSecondPoint, mLastSecondPoint) > mTouchSlop
- || distanceBetween(mDownPoint, mLastPoint) > mTouchSlop)) {
- pilferPointers();
- mThresholdCrossed = true;
- // Reset the down to begin resizing from this point
- mDownPoint.set(mLastPoint);
- mDownSecondPoint.set(mLastSecondPoint);
-
- if (mPhonePipMenuController.isMenuVisible()) {
- mPhonePipMenuController.hideMenu();
- }
- }
-
- if (mThresholdCrossed) {
- mAngle = mPinchResizingAlgorithm.calculateBoundsAndAngle(mDownPoint,
- mDownSecondPoint, mLastPoint, mLastSecondPoint, mMinSize, mMaxSize,
- mDownBounds, mLastResizeBounds);
-
- mPipScheduler.scheduleUserResizePip(mLastResizeBounds, mAngle);
- mPipBoundsState.setHasUserResizedPip(true);
- }
- }
- }
-
private void snapToMovementBoundsEdge(Rect bounds, Rect movementBounds) {
final int leftEdge = bounds.left;
@@ -404,17 +391,21 @@ public class PipResizeGestureHandler implements
// mPipTaskOrganizer.scheduleFinishResizePip(finalBounds, mUpdateResizeBoundsCallback);
}
- private void finishResize() {
+ /** Handles additional resizing and state changes after gesture resizing is done. */
+ void finishResize() {
if (mLastResizeBounds.isEmpty()) {
resetState();
}
- if (!mOngoingPinchToResize) {
- return;
- }
// Cache initial bounds after release for animation before mLastResizeBounds are modified.
mStartBoundsAfterRelease.set(mLastResizeBounds);
+ // Drag-corner-to-resize - we don't need to adjust the bounds at this point
+ if (!mOngoingPinchToResize) {
+ scheduleBoundsChange();
+ return;
+ }
+
// If user resize is pretty close to max size, just auto resize to max.
if (mLastResizeBounds.width() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.x
|| mLastResizeBounds.height() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.y) {
@@ -438,6 +429,10 @@ public class PipResizeGestureHandler implements
mLastResizeBounds, movementBounds);
mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds, snapFraction);
+ scheduleBoundsChange();
+ }
+
+ private void scheduleBoundsChange() {
// Update the transition state to schedule a resize transition.
Bundle extra = new Bundle();
extra.putBoolean(RESIZE_BOUNDS_CHANGE, true);
@@ -489,10 +484,6 @@ public class PipResizeGestureHandler implements
mOhmOffset = offset;
}
- private float distanceBetween(PointF p1, PointF p2) {
- return (float) Math.hypot(p2.x - p1.x, p2.y - p1.y);
- }
-
private void resizeRectAboutCenter(Rect rect, int w, int h) {
int cx = rect.centerX();
int cy = rect.centerY();
@@ -573,6 +564,7 @@ public class PipResizeGestureHandler implements
pw.println(innerPrefix + "mIsAttached=" + mIsAttached);
pw.println(innerPrefix + "mIsEnabled=" + mIsEnabled);
pw.println(innerPrefix + "mEnablePinchResize=" + mEnablePinchResize);
+ pw.println(innerPrefix + "mEnableDragCornerResize=" + mEnableDragCornerResize);
pw.println(innerPrefix + "mThresholdCrossed=" + mThresholdCrossed);
pw.println(innerPrefix + "mOhmOffset=" + mOhmOffset);
pw.println(innerPrefix + "mMinSize=" + mMinSize);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index e17587ff18bc..df7a25af8376 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -35,6 +35,10 @@ import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.shared.split.SplitScreenConstants;
+import com.android.wm.shell.splitscreen.SplitScreenController;
+
+import java.util.Optional;
/**
* Scheduler for Shell initiated PiP transitions and animations.
@@ -47,6 +51,7 @@ public class PipScheduler {
private final ShellExecutor mMainExecutor;
private final PipTransitionState mPipTransitionState;
private final PipDesktopState mPipDesktopState;
+ private final Optional<SplitScreenController> mSplitScreenControllerOptional;
private PipTransitionController mPipTransitionController;
private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
@@ -59,12 +64,14 @@ public class PipScheduler {
PipBoundsState pipBoundsState,
ShellExecutor mainExecutor,
PipTransitionState pipTransitionState,
+ Optional<SplitScreenController> splitScreenControllerOptional,
PipDesktopState pipDesktopState) {
mContext = context;
mPipBoundsState = pipBoundsState;
mMainExecutor = mainExecutor;
mPipTransitionState = pipTransitionState;
mPipDesktopState = pipDesktopState;
+ mSplitScreenControllerOptional = splitScreenControllerOptional;
mSurfaceControlTransactionFactory =
new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
@@ -96,10 +103,23 @@ public class PipScheduler {
public void scheduleExitPipViaExpand() {
mMainExecutor.execute(() -> {
if (!mPipTransitionState.isInPip()) return;
- WindowContainerTransaction wct = getExitPipViaExpandTransaction();
- if (wct != null) {
- mPipTransitionController.startExpandTransition(wct);
- }
+
+ final WindowContainerTransaction expandWct = getExitPipViaExpandTransaction();
+ if (expandWct == null) return;
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ mSplitScreenControllerOptional.ifPresent(splitScreenController -> {
+ int lastParentTaskId = mPipTransitionState.getPipTaskInfo()
+ .lastParentTaskIdBeforePip;
+ if (splitScreenController.isTaskInSplitScreen(lastParentTaskId)) {
+ splitScreenController.prepareEnterSplitScreen(wct,
+ null /* taskInfo */, SplitScreenConstants.SPLIT_POSITION_UNDEFINED);
+ }
+ });
+
+ boolean toSplit = !wct.isEmpty();
+ wct.merge(expandWct, true /* transfer */);
+ mPipTransitionController.startExpandTransition(wct, toSplit);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index e405f3339054..72346b335a8e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -59,6 +59,7 @@ import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipDesktopState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
import com.android.wm.shell.common.pip.PipDoubleTapHelper;
import com.android.wm.shell.common.pip.PipPerfHintController;
@@ -187,6 +188,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
@NonNull PipScheduler pipScheduler,
@NonNull SizeSpecSource sizeSpecSource,
@NonNull PipDisplayLayoutState pipDisplayLayoutState,
+ PipDesktopState pipDesktopState,
DisplayController displayController,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
@@ -226,7 +228,8 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
mainExecutor);
mPipResizeGestureHandler = new PipResizeGestureHandler(context, pipBoundsAlgorithm,
pipBoundsState, mTouchState, mPipScheduler, mPipTransitionState, pipUiEventLogger,
- menuController, mPipDisplayLayoutState, mainExecutor, mPipPerfHintController);
+ menuController, this::getMovementBounds, mPipDisplayLayoutState, pipDesktopState,
+ mainExecutor, mPipPerfHintController);
mPipBoundsState.addOnAspectRatioChangedCallback(aspectRatio -> {
updateMinMaxSize(aspectRatio);
onAspectRatioChanged();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index a57b4b948b42..035c93db7ee4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -16,7 +16,6 @@
package com.android.wm.shell.pip2.phone;
-import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Surface.ROTATION_0;
@@ -29,7 +28,13 @@ import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static com.android.wm.shell.pip2.phone.transition.PipTransitionUtils.getChangeByToken;
+import static com.android.wm.shell.pip2.phone.transition.PipTransitionUtils.getFixedRotationDelta;
+import static com.android.wm.shell.pip2.phone.transition.PipTransitionUtils.getLeash;
+import static com.android.wm.shell.pip2.phone.transition.PipTransitionUtils.getPipChange;
+import static com.android.wm.shell.pip2.phone.transition.PipTransitionUtils.getPipParams;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_RESIZE_PIP;
import static com.android.wm.shell.transition.Transitions.transitTypeToString;
@@ -45,7 +50,6 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -70,11 +74,14 @@ import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
import com.android.wm.shell.pip2.animation.PipEnterAnimator;
-import com.android.wm.shell.pip2.animation.PipExpandAnimator;
+import com.android.wm.shell.pip2.phone.transition.PipExpandHandler;
import com.android.wm.shell.shared.TransitionUtil;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
+import java.util.Optional;
+
/**
* Implementation of transitions for PiP on phone.
*/
@@ -130,6 +137,7 @@ public class PipTransition extends PipTransitionController implements
//
// Internal state and relevant cached info
//
+ private final PipExpandHandler mExpandHandler;
private Transitions.TransitionFinishCallback mFinishCallback;
@@ -151,6 +159,7 @@ public class PipTransition extends PipTransitionController implements
PipDisplayLayoutState pipDisplayLayoutState,
PipUiStateChangeController pipUiStateChangeController,
DisplayController displayController,
+ Optional<SplitScreenController> splitScreenControllerOptional,
PipDesktopState pipDesktopState) {
super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController,
pipBoundsAlgorithm);
@@ -165,6 +174,9 @@ public class PipTransition extends PipTransitionController implements
mDisplayController = displayController;
mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(mContext);
mPipDesktopState = pipDesktopState;
+
+ mExpandHandler = new PipExpandHandler(mContext, pipBoundsState, pipBoundsAlgorithm,
+ pipTransitionState, pipDisplayLayoutState, splitScreenControllerOptional);
}
@Override
@@ -184,10 +196,11 @@ public class PipTransition extends PipTransitionController implements
//
@Override
- public void startExpandTransition(WindowContainerTransaction out) {
+ public void startExpandTransition(WindowContainerTransaction out, boolean toSplit) {
if (out == null) return;
mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
- mExitViaExpandTransition = mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this);
+ mExitViaExpandTransition = mTransitions.startTransition(toSplit ? TRANSIT_EXIT_PIP_TO_SPLIT
+ : TRANSIT_EXIT_PIP, out, this);
}
@Override
@@ -239,10 +252,11 @@ public class PipTransition extends PipTransitionController implements
@NonNull SurfaceControl.Transaction finishT,
@NonNull IBinder mergeTarget,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- // Just jump-cut the current animation if any, but do not merge.
if (info.getType() == TRANSIT_EXIT_PIP) {
end();
}
+ mExpandHandler.mergeAnimation(transition, info, startT, finishT, mergeTarget,
+ finishCallback);
}
@Override
@@ -290,7 +304,8 @@ public class PipTransition extends PipTransitionController implements
finishCallback);
} else if (transition == mExitViaExpandTransition) {
mExitViaExpandTransition = null;
- return startExpandAnimation(info, startTransaction, finishTransaction, finishCallback);
+ return mExpandHandler.startAnimation(transition, info, startTransaction,
+ finishTransaction, finishCallback);
} else if (transition == mResizeTransition) {
mResizeTransition = null;
return startResizeAnimation(info, startTransaction, finishTransaction, finishCallback);
@@ -300,6 +315,9 @@ public class PipTransition extends PipTransitionController implements
mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
return startRemoveAnimation(info, startTransaction, finishTransaction, finishCallback);
}
+ // For any unhandled transition, make sure the PiP surface is properly updated,
+ // i.e. corner and shadow radius.
+ syncPipSurfaceState(info, startTransaction, finishTransaction);
return false;
}
@@ -433,7 +451,7 @@ public class PipTransition extends PipTransitionController implements
(destinationBounds.height() - overlaySize) / 2f);
}
- final int delta = getFixedRotationDelta(info, pipChange);
+ final int delta = getFixedRotationDelta(info, pipChange, mPipDisplayLayoutState);
if (delta != ROTATION_0) {
// Update transition target changes in place to prepare for fixed rotation.
handleBoundsEnterFixedRotation(info, pipChange, pipActivityChange);
@@ -493,7 +511,7 @@ public class PipTransition extends PipTransitionController implements
final Rect adjustedSourceRectHint = getAdjustedSourceRectHint(info, pipChange,
pipActivityChange);
- final int delta = getFixedRotationDelta(info, pipChange);
+ final int delta = getFixedRotationDelta(info, pipChange, mPipDisplayLayoutState);
if (delta != ROTATION_0) {
// Update transition target changes in place to prepare for fixed rotation.
handleBoundsEnterFixedRotation(info, pipChange, pipActivityChange);
@@ -582,27 +600,6 @@ public class PipTransition extends PipTransitionController implements
endBounds.top + activityEndOffset.y);
}
- private void handleExpandFixedRotation(TransitionInfo.Change outPipTaskChange, int delta) {
- final Rect endBounds = outPipTaskChange.getEndAbsBounds();
- final int width = endBounds.width();
- final int height = endBounds.height();
- final int left = endBounds.left;
- final int top = endBounds.top;
- int newTop, newLeft;
-
- if (delta == Surface.ROTATION_90) {
- newLeft = top;
- newTop = -(left + width);
- } else {
- newLeft = -(height + top);
- newTop = left;
- }
- // Modify the endBounds, rotating and placing them potentially off-screen, so that
- // as we translate and rotate around the origin, we place them right into the target.
- endBounds.set(newLeft, newTop, newLeft + height, newTop + width);
- }
-
-
private boolean startAlphaTypeEnterAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@@ -630,83 +627,6 @@ public class PipTransition extends PipTransitionController implements
return true;
}
- private boolean startExpandAnimation(@NonNull TransitionInfo info,
- @NonNull SurfaceControl.Transaction startTransaction,
- @NonNull SurfaceControl.Transaction finishTransaction,
- @NonNull Transitions.TransitionFinishCallback finishCallback) {
- WindowContainerToken pipToken = mPipTransitionState.getPipTaskToken();
-
- TransitionInfo.Change pipChange = getChangeByToken(info, pipToken);
- if (pipChange == null) {
- // pipChange is null, check to see if we've reparented the PIP activity for
- // the multi activity case. If so we should use the activity leash instead
- for (TransitionInfo.Change change : info.getChanges()) {
- if (change.getTaskInfo() == null
- && change.getLastParent() != null
- && change.getLastParent().equals(pipToken)) {
- pipChange = change;
- break;
- }
- }
-
- // failsafe
- if (pipChange == null) {
- return false;
- }
- }
- mFinishCallback = finishCallback;
-
- // The parent change if we were in a multi-activity PiP; null if single activity PiP.
- final TransitionInfo.Change parentBeforePip = pipChange.getTaskInfo() == null
- ? getChangeByToken(info, pipChange.getParent()) : null;
- if (parentBeforePip != null) {
- // For multi activity, we need to manually set the leash layer
- startTransaction.setLayer(parentBeforePip.getLeash(), Integer.MAX_VALUE - 1);
- }
-
- final Rect startBounds = pipChange.getStartAbsBounds();
- final Rect endBounds = pipChange.getEndAbsBounds();
- final SurfaceControl pipLeash = getLeash(pipChange);
-
- PictureInPictureParams params = null;
- if (pipChange.getTaskInfo() != null) {
- // single activity
- params = getPipParams(pipChange);
- } else if (parentBeforePip != null && parentBeforePip.getTaskInfo() != null) {
- // multi activity
- params = getPipParams(parentBeforePip);
- }
- final Rect sourceRectHint = PipBoundsAlgorithm.getValidSourceHintRect(params, endBounds,
- startBounds);
-
- // We define delta = startRotation - endRotation, so we need to flip the sign.
- final int delta = -getFixedRotationDelta(info, pipChange);
- if (delta != ROTATION_0) {
- // Update PiP target change in place to prepare for fixed rotation;
- handleExpandFixedRotation(pipChange, delta);
- }
-
- PipExpandAnimator animator = new PipExpandAnimator(mContext, pipLeash,
- startTransaction, finishTransaction, endBounds, startBounds, endBounds,
- sourceRectHint, delta);
- animator.setAnimationEndCallback(() -> {
- if (parentBeforePip != null) {
- // TODO b/377362511: Animate local leash instead to also handle letterbox case.
- // For multi-activity, set the crop to be null
- finishTransaction.setCrop(pipLeash, null);
- }
- finishTransition();
- });
- cacheAndStartTransitionAnimator(animator);
-
- // Save the PiP bounds in case, we re-enter the PiP with the same component.
- float snapFraction = mPipBoundsAlgorithm.getSnapFraction(
- mPipBoundsState.getBounds());
- mPipBoundsState.saveReentryState(snapFraction);
-
- return true;
- }
-
private boolean startRemoveAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@@ -740,29 +660,6 @@ public class PipTransition extends PipTransitionController implements
// Various helpers to resolve transition requests and infos
//
- @Nullable
- private TransitionInfo.Change getPipChange(TransitionInfo info) {
- for (TransitionInfo.Change change : info.getChanges()) {
- if (change.getTaskInfo() != null
- && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) {
- return change;
- }
- }
- return null;
- }
-
- @Nullable
- private TransitionInfo.Change getChangeByToken(TransitionInfo info,
- WindowContainerToken token) {
- for (TransitionInfo.Change change : info.getChanges()) {
- if (change.getTaskInfo() != null
- && change.getTaskInfo().getToken().equals(token)) {
- return change;
- }
- }
- return null;
- }
-
@NonNull
private Rect getAdjustedSourceRectHint(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change pipTaskChange,
@@ -786,8 +683,8 @@ public class PipTransition extends PipTransitionController implements
Rect cutoutInsets = parentBeforePip != null
? parentBeforePip.getTaskInfo().displayCutoutInsets
: pipTaskChange.getTaskInfo().displayCutoutInsets;
- if (cutoutInsets != null
- && getFixedRotationDelta(info, pipTaskChange) == ROTATION_90) {
+ if (cutoutInsets != null && getFixedRotationDelta(info, pipTaskChange,
+ mPipDisplayLayoutState) == ROTATION_90) {
adjustedSourceRectHint.offset(cutoutInsets.left, cutoutInsets.top);
}
if (mPipDesktopState.isDesktopWindowingPipEnabled()) {
@@ -804,25 +701,6 @@ public class PipTransition extends PipTransitionController implements
return adjustedSourceRectHint;
}
- @Surface.Rotation
- private int getFixedRotationDelta(@NonNull TransitionInfo info,
- @NonNull TransitionInfo.Change pipChange) {
- TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
- int startRotation = pipChange.getStartRotation();
- if (pipChange.getEndRotation() != ROTATION_UNDEFINED
- && startRotation != pipChange.getEndRotation()) {
- // If PiP change was collected along with the display change and the orientation change
- // happened in sync with the PiP change, then do not treat this as fixed-rotation case.
- return ROTATION_0;
- }
-
- int endRotation = fixedRotationChange != null
- ? fixedRotationChange.getEndFixedRotation() : mPipDisplayLayoutState.getRotation();
- int delta = endRotation == ROTATION_UNDEFINED ? ROTATION_0
- : startRotation - endRotation;
- return delta;
- }
-
private void prepareOtherTargetTransforms(TransitionInfo info,
SurfaceControl.Transaction startTransaction,
SurfaceControl.Transaction finishTransaction) {
@@ -850,7 +728,8 @@ public class PipTransition extends PipTransitionController implements
// If PiP is enabled on Connected Displays, update PipDisplayLayoutState to have the correct
// display info that PiP is entering in.
- if (mPipDesktopState.isConnectedDisplaysPipEnabled()) {
+ if (mPipDesktopState.isConnectedDisplaysPipEnabled()
+ && pipTask.displayId != mPipDisplayLayoutState.getDisplayId()) {
final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(
pipTask.displayId);
if (displayLayout != null) {
@@ -1009,20 +888,6 @@ public class PipTransition extends PipTransitionController implements
mTransitionAnimator.start();
}
- @NonNull
- private static PictureInPictureParams getPipParams(@NonNull TransitionInfo.Change pipChange) {
- return pipChange.getTaskInfo().pictureInPictureParams != null
- ? pipChange.getTaskInfo().pictureInPictureParams
- : new PictureInPictureParams.Builder().build();
- }
-
- @NonNull
- private static SurfaceControl getLeash(TransitionInfo.Change change) {
- SurfaceControl leash = change.getLeash();
- Preconditions.checkNotNull(leash, "Leash is null for change=" + change);
- return leash;
- }
-
//
// Miscellaneous callbacks and listeners
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
index 8805cbb0dfbd..18c9a705dcf7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
@@ -314,7 +314,8 @@ public class PipTransitionState {
mSwipePipToHomeAppBounds.setEmpty();
}
- @Nullable WindowContainerToken getPipTaskToken() {
+ @Nullable
+ public WindowContainerToken getPipTaskToken() {
return mPipTaskInfo != null ? mPipTaskInfo.getToken() : null;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java
new file mode 100644
index 000000000000..db4942b2fb95
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.pip2.phone.transition;
+
+import static android.view.Surface.ROTATION_0;
+
+import static com.android.wm.shell.pip2.phone.transition.PipTransitionUtils.getChangeByToken;
+import static com.android.wm.shell.pip2.phone.transition.PipTransitionUtils.getFixedRotationDelta;
+import static com.android.wm.shell.pip2.phone.transition.PipTransitionUtils.getLeash;
+import static com.android.wm.shell.pip2.phone.transition.PipTransitionUtils.getPipParams;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
+
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PictureInPictureParams;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.ProtoLog;
+import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+import com.android.wm.shell.pip2.animation.PipExpandAnimator;
+import com.android.wm.shell.pip2.phone.PipTransitionState;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.transition.Transitions;
+
+import java.util.Optional;
+
+public class PipExpandHandler implements Transitions.TransitionHandler {
+ private final Context mContext;
+ private final PipBoundsState mPipBoundsState;
+ private final PipBoundsAlgorithm mPipBoundsAlgorithm;
+ private final PipTransitionState mPipTransitionState;
+ private final PipDisplayLayoutState mPipDisplayLayoutState;
+ private final Optional<SplitScreenController> mSplitScreenControllerOptional;
+
+ @Nullable
+ private Transitions.TransitionFinishCallback mFinishCallback;
+ @Nullable
+ private ValueAnimator mTransitionAnimator;
+
+ private PipExpandAnimatorSupplier mPipExpandAnimatorSupplier;
+
+ public PipExpandHandler(Context context,
+ PipBoundsState pipBoundsState,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipTransitionState pipTransitionState,
+ PipDisplayLayoutState pipDisplayLayoutState,
+ Optional<SplitScreenController> splitScreenControllerOptional) {
+ mContext = context;
+ mPipBoundsState = pipBoundsState;
+ mPipBoundsAlgorithm = pipBoundsAlgorithm;
+ mPipTransitionState = pipTransitionState;
+ mPipDisplayLayoutState = pipDisplayLayoutState;
+ mSplitScreenControllerOptional = splitScreenControllerOptional;
+
+ mPipExpandAnimatorSupplier = PipExpandAnimator::new;
+ }
+
+ @Override
+ public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+ @NonNull TransitionRequestInfo request) {
+ // All Exit-via-Expand from PiP transitions are Shell initiated.
+ return null;
+ }
+
+ @Override
+ public boolean startAnimation(@NonNull IBinder transition,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ switch (info.getType()) {
+ case TRANSIT_EXIT_PIP:
+ return startExpandAnimation(info, startTransaction, finishTransaction,
+ finishCallback);
+ case TRANSIT_EXIT_PIP_TO_SPLIT:
+ return startExpandToSplitAnimation(info, startTransaction, finishTransaction,
+ finishCallback);
+ }
+ return false;
+ }
+
+ @Override
+ public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ end();
+ }
+
+ /**
+ * Ends the animation if such is running in the context of expanding out of PiP.
+ */
+ public void end() {
+ if (mTransitionAnimator != null && mTransitionAnimator.isRunning()) {
+ mTransitionAnimator.end();
+ mTransitionAnimator = null;
+ }
+ }
+
+ private boolean startExpandAnimation(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ WindowContainerToken pipToken = mPipTransitionState.getPipTaskToken();
+
+ TransitionInfo.Change pipChange = getChangeByToken(info, pipToken);
+ if (pipChange == null) {
+ // pipChange is null, check to see if we've reparented the PIP activity for
+ // the multi activity case. If so we should use the activity leash instead
+ for (TransitionInfo.Change change : info.getChanges()) {
+ if (change.getTaskInfo() == null
+ && change.getLastParent() != null
+ && change.getLastParent().equals(pipToken)) {
+ pipChange = change;
+ break;
+ }
+ }
+
+ // failsafe
+ if (pipChange == null) {
+ return false;
+ }
+ }
+ mFinishCallback = finishCallback;
+
+ // The parent change if we were in a multi-activity PiP; null if single activity PiP.
+ final TransitionInfo.Change parentBeforePip = pipChange.getTaskInfo() == null
+ ? getChangeByToken(info, pipChange.getParent()) : null;
+ if (parentBeforePip != null) {
+ // For multi activity, we need to manually set the leash layer
+ startTransaction.setLayer(parentBeforePip.getLeash(), Integer.MAX_VALUE - 1);
+ }
+
+ final Rect startBounds = pipChange.getStartAbsBounds();
+ final Rect endBounds = pipChange.getEndAbsBounds();
+ final SurfaceControl pipLeash = getLeash(pipChange);
+
+ PictureInPictureParams params = null;
+ if (pipChange.getTaskInfo() != null) {
+ // single activity
+ params = getPipParams(pipChange);
+ } else if (parentBeforePip != null && parentBeforePip.getTaskInfo() != null) {
+ // multi activity
+ params = getPipParams(parentBeforePip);
+ }
+ final Rect sourceRectHint = PipBoundsAlgorithm.getValidSourceHintRect(params, endBounds,
+ startBounds);
+
+ // We define delta = startRotation - endRotation, so we need to flip the sign.
+ final int delta = -getFixedRotationDelta(info, pipChange, mPipDisplayLayoutState);
+ if (delta != ROTATION_0) {
+ // Update PiP target change in place to prepare for fixed rotation;
+ handleExpandFixedRotation(pipChange, delta);
+ }
+
+ PipExpandAnimator animator = mPipExpandAnimatorSupplier.get(mContext, pipLeash,
+ startTransaction, finishTransaction, endBounds, startBounds, endBounds,
+ sourceRectHint, delta);
+ animator.setAnimationEndCallback(() -> {
+ if (parentBeforePip != null) {
+ // TODO b/377362511: Animate local leash instead to also handle letterbox case.
+ // For multi-activity, set the crop to be null
+ finishTransaction.setCrop(pipLeash, null);
+ }
+ finishTransition();
+ });
+ cacheAndStartTransitionAnimator(animator);
+ saveReentryState();
+ return true;
+ }
+
+ private boolean startExpandToSplitAnimation(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ WindowContainerToken pipToken = mPipTransitionState.getPipTaskToken();
+
+ // Expanding PiP to Split-screen makes sense only if we are dealing with multi-activity PiP
+ // and the lastParentBeforePip is still in one of the split-stages.
+ //
+ // This means we should be animating the PiP activity leash, since we do the reparenting
+ // of the PiP activity back to its original task in startWCT.
+ TransitionInfo.Change pipChange = null;
+ for (TransitionInfo.Change change : info.getChanges()) {
+ if (change.getTaskInfo() == null
+ && change.getLastParent() != null
+ && change.getLastParent().equals(pipToken)) {
+ pipChange = change;
+ break;
+ }
+ }
+ // failsafe
+ if (pipChange == null || pipChange.getLeash() == null) {
+ return false;
+ }
+ mFinishCallback = finishCallback;
+
+ // Get the original parent before PiP. If original task hosting the PiP activity was
+ // already visible, then it's not participating in this transition; in that case,
+ // parentBeforePip would be null.
+ final TransitionInfo.Change parentBeforePip = getChangeByToken(info, pipChange.getParent());
+
+ final Rect startBounds = pipChange.getStartAbsBounds();
+ final Rect endBounds = pipChange.getEndAbsBounds();
+ if (parentBeforePip != null) {
+ // Since we have the parent task amongst the targets, all PiP activity
+ // leash translations will be relative to the original task, NOT the root leash.
+ startBounds.offset(-parentBeforePip.getStartAbsBounds().left,
+ -parentBeforePip.getStartAbsBounds().top);
+ endBounds.offset(-parentBeforePip.getEndAbsBounds().left,
+ -parentBeforePip.getEndAbsBounds().top);
+ }
+
+ final SurfaceControl pipLeash = pipChange.getLeash();
+ PipExpandAnimator animator = mPipExpandAnimatorSupplier.get(mContext, pipLeash,
+ startTransaction, finishTransaction, endBounds, startBounds, endBounds,
+ null /* srcRectHint */, ROTATION_0 /* delta */);
+
+
+ mSplitScreenControllerOptional.ifPresent(splitController -> {
+ splitController.finishEnterSplitScreen(finishTransaction);
+ });
+
+ animator.setAnimationEndCallback(() -> {
+ if (parentBeforePip == null) {
+ // After PipExpandAnimator is done modifying finishTransaction, we need to make
+ // sure PiP activity leash is offset at origin relative to its task as we reparent
+ // targets back from the transition root leash.
+ finishTransaction.setPosition(pipLeash, 0, 0);
+ }
+ finishTransition();
+ });
+ cacheAndStartTransitionAnimator(animator);
+ saveReentryState();
+ return true;
+ }
+
+ private void finishTransition() {
+ final int currentState = mPipTransitionState.getState();
+ if (currentState != PipTransitionState.EXITING_PIP) {
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "Unexpected state %s as we are finishing an exit-via-expand transition",
+ mPipTransitionState);
+ }
+ mPipTransitionState.setState(PipTransitionState.EXITED_PIP);
+
+ if (mFinishCallback != null) {
+ // Need to unset mFinishCallback first because onTransitionFinished can re-enter this
+ // handler if there is a pending PiP animation.
+ final Transitions.TransitionFinishCallback finishCallback = mFinishCallback;
+ mFinishCallback = null;
+ finishCallback.onTransitionFinished(null /* finishWct */);
+ }
+ }
+
+ private void handleExpandFixedRotation(TransitionInfo.Change outPipTaskChange, int delta) {
+ final Rect endBounds = outPipTaskChange.getEndAbsBounds();
+ final int width = endBounds.width();
+ final int height = endBounds.height();
+ final int left = endBounds.left;
+ final int top = endBounds.top;
+ int newTop, newLeft;
+
+ if (delta == Surface.ROTATION_90) {
+ newLeft = top;
+ newTop = -(left + width);
+ } else {
+ newLeft = -(height + top);
+ newTop = left;
+ }
+ // Modify the endBounds, rotating and placing them potentially off-screen, so that
+ // as we translate and rotate around the origin, we place them right into the target.
+ endBounds.set(newLeft, newTop, newLeft + height, newTop + width);
+ }
+
+ private void saveReentryState() {
+ float snapFraction = mPipBoundsAlgorithm.getSnapFraction(
+ mPipBoundsState.getBounds());
+ mPipBoundsState.saveReentryState(snapFraction);
+ }
+
+ private void cacheAndStartTransitionAnimator(@NonNull ValueAnimator animator) {
+ mTransitionAnimator = animator;
+ mTransitionAnimator.start();
+ }
+
+ @VisibleForTesting
+ interface PipExpandAnimatorSupplier {
+ PipExpandAnimator get(Context context,
+ @NonNull SurfaceControl leash,
+ SurfaceControl.Transaction startTransaction,
+ SurfaceControl.Transaction finishTransaction,
+ @NonNull Rect baseBounds,
+ @NonNull Rect startBounds,
+ @NonNull Rect endBounds,
+ @Nullable Rect sourceRectHint,
+ @Surface.Rotation int rotation);
+ }
+
+ @VisibleForTesting
+ void setPipExpandAnimatorSupplier(@NonNull PipExpandAnimatorSupplier supplier) {
+ mPipExpandAnimatorSupplier = supplier;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipTransitionUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipTransitionUtils.java
new file mode 100644
index 000000000000..01cda6c91108
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipTransitionUtils.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.pip2.phone.transition;
+
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.Surface.ROTATION_0;
+
+import android.annotation.NonNull;
+import android.app.PictureInPictureParams;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
+import android.window.WindowContainerToken;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.util.Preconditions;
+import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+
+/**
+ * A set of utility methods to help resolve PiP transitions.
+ */
+public class PipTransitionUtils {
+
+ /**
+ * @return change for a pinned mode task; null if no such task is in the list of changes.
+ */
+ @Nullable
+ public static TransitionInfo.Change getPipChange(TransitionInfo info) {
+ for (TransitionInfo.Change change : info.getChanges()) {
+ if (change.getTaskInfo() != null
+ && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) {
+ return change;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return change for a task with the provided token; null if no task with such token found.
+ */
+ @Nullable
+ public static TransitionInfo.Change getChangeByToken(TransitionInfo info,
+ WindowContainerToken token) {
+ for (TransitionInfo.Change change : info.getChanges()) {
+ if (change.getTaskInfo() != null
+ && change.getTaskInfo().getToken().equals(token)) {
+ return change;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return the leash to interact with the container this change represents.
+ * @throws NullPointerException if the leash is null.
+ */
+ @NonNull
+ public static SurfaceControl getLeash(TransitionInfo.Change change) {
+ SurfaceControl leash = change.getLeash();
+ Preconditions.checkNotNull(leash, "Leash is null for change=" + change);
+ return leash;
+ }
+
+ /**
+ * Get the rotation delta in a potential fixed rotation transition.
+ *
+ * Whenever PiP participates in fixed rotation, its actual orientation isn't updated
+ * in the initial transition as per the async rotation convention.
+ *
+ * @param pipChange PiP change to verify that PiP task's rotation wasn't updated already.
+ * @param pipDisplayLayoutState display layout state that PiP component keeps track of.
+ */
+ @Surface.Rotation
+ public static int getFixedRotationDelta(@NonNull TransitionInfo info,
+ @NonNull TransitionInfo.Change pipChange,
+ @NonNull PipDisplayLayoutState pipDisplayLayoutState) {
+ TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
+ int startRotation = pipChange.getStartRotation();
+ if (pipChange.getEndRotation() != ROTATION_UNDEFINED
+ && startRotation != pipChange.getEndRotation()) {
+ // If PiP change was collected along with the display change and the orientation change
+ // happened in sync with the PiP change, then do not treat this as fixed-rotation case.
+ return ROTATION_0;
+ }
+
+ int endRotation = fixedRotationChange != null
+ ? fixedRotationChange.getEndFixedRotation() : pipDisplayLayoutState.getRotation();
+ int delta = endRotation == ROTATION_UNDEFINED ? ROTATION_0
+ : startRotation - endRotation;
+ return delta;
+ }
+
+ /**
+ * Gets a change amongst the transition targets that is in a different final orientation than
+ * the display, signalling a potential fixed rotation transition.
+ */
+ @Nullable
+ public static TransitionInfo.Change findFixedRotationChange(@NonNull TransitionInfo info) {
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getEndFixedRotation() != ROTATION_UNDEFINED) {
+ return change;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return {@link PictureInPictureParams} provided by the client from the PiP change.
+ */
+ @NonNull
+ public static PictureInPictureParams getPipParams(@NonNull TransitionInfo.Change pipChange) {
+ return pipChange.getTaskInfo().pictureInPictureParams != null
+ ? pipChange.getTaskInfo().pictureInPictureParams
+ : new PictureInPictureParams.Builder().build();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentsAnimationRunner.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentsAnimationRunner.aidl
index 8cdb8c4512a9..f8d84e4f3c21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentsAnimationRunner.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentsAnimationRunner.aidl
@@ -59,11 +59,12 @@ oneway interface IRecentsAnimationRunner {
void onAnimationStart(in IRecentsAnimationController controller,
in RemoteAnimationTarget[] apps, in RemoteAnimationTarget[] wallpapers,
in Rect homeContentInsets, in Rect minimizedHomeBounds, in Bundle extras,
- in TransitionInfo info) = 2;
+ in @nullable TransitionInfo info) = 2;
/**
* Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control.
*/
- void onTasksAppeared(in RemoteAnimationTarget[] app) = 3;
+ void onTasksAppeared(in RemoteAnimationTarget[] app,
+ in @nullable TransitionInfo transitionInfo) = 3;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 4f2e028a1df0..2fa09664b73f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -381,7 +381,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
private void notifyRunningTaskAppeared(RunningTaskInfo taskInfo) {
if (mListener == null
|| !shouldEnableRunningTasksForDesktopMode()
- || taskInfo.realActivity == null) {
+ || taskInfo.realActivity == null
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
@@ -397,7 +398,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
private void notifyRunningTaskChanged(RunningTaskInfo taskInfo) {
if (mListener == null
|| !shouldEnableRunningTasksForDesktopMode()
- || taskInfo.realActivity == null) {
+ || taskInfo.realActivity == null
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
@@ -413,7 +415,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
private void notifyRunningTaskVanished(RunningTaskInfo taskInfo) {
if (mListener == null
|| !shouldEnableRunningTasksForDesktopMode()
- || taskInfo.realActivity == null) {
+ || taskInfo.realActivity == null
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
@@ -430,7 +433,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
if (mListener == null
|| !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
|| taskInfo.realActivity == null
- || enableShellTopTaskTracking()) {
+ || enableShellTopTaskTracking()
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
@@ -447,7 +451,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
if (mListener == null
|| !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
|| taskInfo.realActivity == null
- || enableShellTopTaskTracking()) {
+ || enableShellTopTaskTracking()
+ || excludeTaskFromGeneratedList(taskInfo)) {
return;
}
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 7751741ae082..847a0383e7d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -796,7 +796,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
" unhandled root taskId=%d", taskInfo.taskId);
}
- } else if (TransitionUtil.isDividerBar(change)) {
+ } else if (TransitionUtil.isDividerBar(change)
+ || TransitionUtil.isDimLayer(change)) {
final RemoteAnimationTarget target = TransitionUtil.newTarget(change,
belowLayers - i, info, t, mLeashMap);
// Add this as a app and we will separate them on launcher side by window type.
@@ -1214,13 +1215,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
// Since we're accepting the merge, update the finish transaction so that changes via
// that transaction will be applied on top of those of the merged transitions
mFinishTransaction = finishT;
- // not using the incoming anim-only surfaces
- info.releaseAnimSurfaces();
+ boolean passTransitionInfo = ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX.isTrue();
+ if (!passTransitionInfo) {
+ // not using the incoming anim-only surfaces
+ info.releaseAnimSurfaces();
+ }
if (appearedTargets != null) {
try {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.merge: calling onTasksAppeared", mInstanceId);
- mListener.onTasksAppeared(appearedTargets);
+ mListener.onTasksAppeared(appearedTargets, passTransitionInfo ? info : null);
} catch (RemoteException e) {
Slog.e(TAG, "Error sending appeared tasks to recents animation", e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index e9f8a4a86d27..ba30d924e0b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -638,6 +638,14 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
}
/**
+ * Starts an existing task via StageCoordinator.
+ */
+ public void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options,
+ @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) {
+ mStageCoordinator.startTask(taskId, position, options, hideTaskToken, index);
+ }
+
+ /**
* See {@link #startShortcut(String, String, int, Bundle, UserHandle)}
* @param instanceId to be used by {@link SplitscreenEventLogger}
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a799b7f2580e..73b42d6f007c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -40,11 +40,13 @@ import static com.android.wm.shell.Flags.enableFlexibleSplit;
import static com.android.wm.shell.Flags.enableFlexibleTwoAppSplit;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_FLEX;
+import static com.android.wm.shell.common.split.SplitLayout.RESTING_DIM_LAYER;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIM_LAYER;
import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
@@ -1824,6 +1826,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Ensure divider surface are re-parented back into the hierarchy at the end of the
// transition. See Transition#buildFinishTransaction for more detail.
finishT.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash);
+ if (Flags.enableFlexibleSplit()) {
+ mStageOrderOperator.getActiveStages().forEach(stage -> {
+ finishT.reparent(stage.mDimLayer, stage.mRootLeash);
+ });
+ } else if (Flags.enableFlexibleTwoAppSplit()) {
+ finishT.reparent(mMainStage.mDimLayer, mMainStage.mRootLeash);
+ finishT.reparent(mSideStage.mDimLayer, mSideStage.mRootLeash);
+ }
updateSurfaceBounds(mSplitLayout, finishT, false /* applyResizingOffset */);
finishT.show(mRootTaskLeash);
@@ -3540,6 +3550,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
finishEnterSplitScreen(finishT);
addDividerBarToTransition(info, true /* show */);
+ if (Flags.enableFlexibleTwoAppSplit()) {
+ addAllDimLayersToTransition(info, true /* show */);
+ }
return true;
}
@@ -3790,6 +3803,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
addDividerBarToTransition(info, false /* show */);
+ if (Flags.enableFlexibleTwoAppSplit()) {
+ addAllDimLayersToTransition(info, false /* show */);
+ }
}
/** Call this when the recents animation canceled during split-screen. */
@@ -3836,6 +3852,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
returnToApp);
mPausingTasks.clear();
if (returnToApp) {
+ // Reparent auxiliary surfaces (divider bar and dim layers) back onto their
+ // original roots.
+ if (Flags.enableFlexibleSplit()) {
+ mStageOrderOperator.getActiveStages().forEach(stage -> {
+ finishT.reparent(stage.mDimLayer, stage.mRootLeash);
+ finishT.setLayer(stage.mDimLayer, RESTING_DIM_LAYER);
+ });
+ } else if (Flags.enableFlexibleTwoAppSplit()) {
+ finishT.reparent(mMainStage.mDimLayer, mMainStage.mRootLeash);
+ finishT.reparent(mSideStage.mDimLayer, mSideStage.mRootLeash);
+ finishT.setLayer(mMainStage.mDimLayer, RESTING_DIM_LAYER);
+ finishT.setLayer(mSideStage.mDimLayer, RESTING_DIM_LAYER);
+ }
updateSurfaceBounds(mSplitLayout, finishT,
false /* applyResizingOffset */);
finishT.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash);
@@ -3902,6 +3931,39 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
info.addChange(barChange);
}
+ /** Add dim layers to the transition, so that they can be hidden/shown when animation starts. */
+ private void addAllDimLayersToTransition(@NonNull TransitionInfo info, boolean show) {
+ if (Flags.enableFlexibleSplit()) {
+ List<StageTaskListener> stages = mStageOrderOperator.getActiveStages();
+ for (int i = 0; i < stages.size(); i++) {
+ final StageTaskListener stage = stages.get(i);
+ mSplitState.getCurrentLayout().get(i).roundOut(mTempRect1);
+ addDimLayerToTransition(info, show, stage, mTempRect1);
+ }
+ } else {
+ addDimLayerToTransition(info, show, mMainStage, getMainStageBounds());
+ addDimLayerToTransition(info, show, mSideStage, getSideStageBounds());
+ }
+ }
+
+ /** Adds a single dim layer to the given TransitionInfo. */
+ private void addDimLayerToTransition(@NonNull TransitionInfo info, boolean show,
+ StageTaskListener stage, Rect bounds) {
+ final SurfaceControl dimLayer = stage.mDimLayer;
+ if (dimLayer == null || !dimLayer.isValid()) {
+ Slog.w(TAG, "addDimLayerToTransition but leash was released or not created");
+ } else {
+ final TransitionInfo.Change change =
+ new TransitionInfo.Change(null /* token */, dimLayer);
+ change.setParent(mRootTaskInfo.token);
+ change.setStartAbsBounds(bounds);
+ change.setEndAbsBounds(bounds);
+ change.setMode(show ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK);
+ change.setFlags(FLAG_IS_DIM_LAYER);
+ info.addChange(change);
+ }
+ }
+
@NeverCompile
@Override
public void dump(@NonNull PrintWriter pw, String prefix) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index deb8839bd319..e28a7fa159c5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -197,6 +197,9 @@ public class Transitions implements RemoteCallable<Transitions>,
/** Transition type for app compat reachability. */
public static final int TRANSIT_MOVE_LETTERBOX_REACHABILITY = TRANSIT_FIRST_CUSTOM + 23;
+ /** Transition type for converting a task to a bubble. */
+ public static final int TRANSIT_CONVERT_TO_BUBBLE = TRANSIT_FIRST_CUSTOM + 24;
+
/** Transition type for desktop mode transitions. */
public static final int TRANSIT_DESKTOP_MODE_TYPES =
WindowManager.TRANSIT_FIRST_CUSTOM + 100;
@@ -1869,6 +1872,7 @@ public class Transitions implements RemoteCallable<Transitions>,
case TRANSIT_MINIMIZE -> "MINIMIZE";
case TRANSIT_START_RECENTS_TRANSITION -> "START_RECENTS_TRANSITION";
case TRANSIT_END_RECENTS_TRANSITION -> "END_RECENTS_TRANSITION";
+ case TRANSIT_CONVERT_TO_BUBBLE -> "CONVERT_TO_BUBBLE";
default -> "";
};
if (typeStr.isEmpty()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 7aa00370ff58..dd5439a8aa10 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -389,7 +389,9 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT
} else if (id == R.id.back_button) {
mTaskOperations.injectBackKey(mDisplayId);
} else if (id == R.id.minimize_window) {
- mTaskOperations.minimizeTask(mTaskToken);
+ // This minimize button uses the same effect for any minimization. The last argument
+ // doesn't matter.
+ mTaskOperations.minimizeTask(mTaskToken, mTaskId, /* isLastTask= */ false);
} else if (id == R.id.maximize_window) {
RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
final DisplayAreaInfo rootDisplayAreaInfo =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 1cc04b421132..5a6ea214e561 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -149,6 +149,8 @@ import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.extension.InsetsStateKt;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
+import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel;
+import com.android.wm.shell.windowdecor.tiling.SnapEventHandler;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
import kotlin.Pair;
@@ -173,7 +175,7 @@ import java.util.function.Supplier;
*/
public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
- FocusTransitionListener {
+ FocusTransitionListener, SnapEventHandler {
private static final String TAG = "DesktopModeWindowDecorViewModel";
private final DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory;
@@ -255,6 +257,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
private final WindowDecorTaskResourceLoader mTaskResourceLoader;
private final RecentsTransitionHandler mRecentsTransitionHandler;
private final DesktopModeCompatPolicy mDesktopModeCompatPolicy;
+ private final DesktopTilingDecorViewModel mDesktopTilingDecorViewModel;
public DesktopModeWindowDecorViewModel(
Context context,
@@ -292,7 +295,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
DesktopModeUiEventLogger desktopModeUiEventLogger,
WindowDecorTaskResourceLoader taskResourceLoader,
RecentsTransitionHandler recentsTransitionHandler,
- DesktopModeCompatPolicy desktopModeCompatPolicy) {
+ DesktopModeCompatPolicy desktopModeCompatPolicy,
+ DesktopTilingDecorViewModel desktopTilingDecorViewModel) {
this(
context,
shellExecutor,
@@ -335,7 +339,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
desktopModeUiEventLogger,
taskResourceLoader,
recentsTransitionHandler,
- desktopModeCompatPolicy);
+ desktopModeCompatPolicy,
+ desktopTilingDecorViewModel);
}
@VisibleForTesting
@@ -381,7 +386,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
DesktopModeUiEventLogger desktopModeUiEventLogger,
WindowDecorTaskResourceLoader taskResourceLoader,
RecentsTransitionHandler recentsTransitionHandler,
- DesktopModeCompatPolicy desktopModeCompatPolicy) {
+ DesktopModeCompatPolicy desktopModeCompatPolicy,
+ DesktopTilingDecorViewModel desktopTilingDecorViewModel) {
mContext = context;
mMainExecutor = shellExecutor;
mMainHandler = mainHandler;
@@ -452,7 +458,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
mTaskResourceLoader = taskResourceLoader;
mRecentsTransitionHandler = recentsTransitionHandler;
mDesktopModeCompatPolicy = desktopModeCompatPolicy;
-
+ mDesktopTilingDecorViewModel = desktopTilingDecorViewModel;
+ mDesktopTasksController.setSnapEventHandler(this);
shellInit.addInitCallback(this::onInit, this);
}
@@ -723,8 +730,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
decoration.mTaskInfo,
left ? SnapPosition.LEFT : SnapPosition.RIGHT,
left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU,
- inputMethod,
- decoration);
+ inputMethod);
decoration.closeHandleMenu();
decoration.closeMaximizeMenu();
@@ -885,6 +891,33 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
return snapshotList;
}
+ @Override
+ public boolean snapToHalfScreen(@NonNull RunningTaskInfo taskInfo,
+ @NonNull Rect currentDragBounds, @NonNull SnapPosition position) {
+ return mDesktopTilingDecorViewModel.snapToHalfScreen(taskInfo,
+ mWindowDecorByTaskId.get(taskInfo.taskId), position, currentDragBounds);
+ }
+
+ @Override
+ public void removeTaskIfTiled(int displayId, int taskId) {
+ mDesktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId);
+ }
+
+ @Override
+ public void onUserChange() {
+ mDesktopTilingDecorViewModel.onUserChange();
+ }
+
+ @Override
+ public void onOverviewAnimationStateChange(boolean running) {
+ mDesktopTilingDecorViewModel.onOverviewAnimationStateChange(running);
+ }
+
+ @Override
+ public boolean moveTaskToFrontIfTiled(@NonNull RunningTaskInfo taskInfo) {
+ return mDesktopTilingDecorViewModel.moveTaskToFrontIfTiled(taskInfo);
+ }
+
private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
View.OnGenericMotionListener, DragDetector.MotionEventHandler {
@@ -951,7 +984,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
mDesktopTasksController.onDesktopWindowClose(
wct, mDisplayId, decoration.mTaskInfo);
final IBinder transition = mTaskOperations.closeTask(mTaskToken, wct);
- if (transition != null && runOnTransitionStart != null) {
+ if (transition != null) {
runOnTransitionStart.invoke(transition);
}
}
@@ -1238,8 +1271,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
taskInfo, decoration.mTaskSurface,
new PointF(e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)),
newTaskBounds, decoration.calculateValidDragArea(),
- new Rect(mOnDragStartInitialBounds), e,
- mWindowDecorByTaskId.get(taskInfo.taskId));
+ new Rect(mOnDragStartInitialBounds), e);
if (touchingButton) {
// We need the input event to not be consumed here to end the ripple
// effect on the touched button. We will reset drag state in the ensuing
@@ -1444,16 +1476,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
relevantDecor.mTaskInfo.configuration.windowConfiguration.getBounds());
boolean dragFromStatusBarAllowed = false;
final int windowingMode = relevantDecor.mTaskInfo.getWindowingMode();
- if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)
+ || BubbleAnythingFlagHelper.enableBubbleToFullscreen()) {
// In proto2 any full screen or multi-window task can be dragged to
// freeform.
dragFromStatusBarAllowed = windowingMode == WINDOWING_MODE_FULLSCREEN
|| windowingMode == WINDOWING_MODE_MULTI_WINDOW;
}
- if (BubbleAnythingFlagHelper.enableBubbleToFullscreen()) {
- // TODO(b/388851898): add support for split screen (multi-window wm mode)
- dragFromStatusBarAllowed = windowingMode == WINDOWING_MODE_FULLSCREEN;
- }
final boolean shouldStartTransitionDrag =
relevantDecor.checkTouchEventInFocusedCaptionHandle(ev)
|| DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue();
@@ -1502,7 +1531,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
// Do not create an indicator at all if we're not past transition height.
DisplayLayout layout = mDisplayController
.getDisplayLayout(relevantDecor.mTaskInfo.displayId);
- if (ev.getRawY() < 2 * layout.stableInsets().top
+ // It's possible task is not at the top of the screen (e.g. bottom of vertical
+ // Splitscreen)
+ final int taskTop = relevantDecor.mTaskInfo.configuration.windowConfiguration
+ .getBounds().top;
+ if (ev.getRawY() < 2 * layout.stableInsets().top + taskTop
&& mMoveToDesktopAnimator == null) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 3fb94630eab3..271dead467b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -803,8 +803,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
if (!mTaskInfo.isVisible()) {
closeMaximizeMenu();
} else {
- final int menuWidth = calculateMaximizeMenuWidth();
- mMaximizeMenu.positionMenu(calculateMaximizeMenuPosition(menuWidth), startT);
+ mMaximizeMenu.positionMenu(startT);
}
}
@@ -1069,27 +1068,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
return Resources.ID_NULL;
}
- private int calculateMaximizeMenuWidth() {
- final boolean showImmersive = DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()
- && TaskInfoKt.getRequestingImmersive(mTaskInfo);
- final boolean showMaximize = true;
- final boolean showSnaps = mTaskInfo.isResizeable;
- int showCount = 0;
- if (showImmersive) showCount++;
- if (showMaximize) showCount++;
- if (showSnaps) showCount++;
- return switch (showCount) {
- case 1 -> loadDimensionPixelSize(mContext.getResources(),
- R.dimen.desktop_mode_maximize_menu_width_one_options);
- case 2 -> loadDimensionPixelSize(mContext.getResources(),
- R.dimen.desktop_mode_maximize_menu_width_two_options);
- case 3 -> loadDimensionPixelSize(mContext.getResources(),
- R.dimen.desktop_mode_maximize_menu_width_three_options);
- default -> throw new IllegalArgumentException("");
- };
- }
-
- private PointF calculateMaximizeMenuPosition(int menuWidth) {
+ private PointF calculateMaximizeMenuPosition(int menuWidth, int menuHeight) {
final PointF position = new PointF();
final Resources resources = mContext.getResources();
final DisplayLayout displayLayout =
@@ -1105,9 +1084,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
final int[] maximizeButtonLocation = new int[2];
maximizeWindowButton.getLocationInWindow(maximizeButtonLocation);
- final int menuHeight = loadDimensionPixelSize(
- resources, R.dimen.desktop_mode_maximize_menu_height);
-
float menuLeft = (mPositionInParent.x + maximizeButtonLocation[0] - ((float) (menuWidth
- maximizeWindowButton.getWidth()) / 2));
float menuTop = (mPositionInParent.y + captionHeight);
@@ -1294,17 +1270,16 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
* Create and display maximize menu window
*/
void createMaximizeMenu() {
- final int menuWidth = calculateMaximizeMenuWidth();
mMaximizeMenu = mMaximizeMenuFactory.create(mSyncQueue, mRootTaskDisplayAreaOrganizer,
mDisplayController, mTaskInfo, mContext,
- calculateMaximizeMenuPosition(menuWidth), mSurfaceControlTransactionSupplier);
+ (width, height) -> calculateMaximizeMenuPosition(width, height),
+ mSurfaceControlTransactionSupplier);
mMaximizeMenu.show(
/* isTaskInImmersiveMode= */
DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()
&& mDesktopUserRepositories.getProfile(mTaskInfo.userId)
.isTaskInFullImmersiveState(mTaskInfo.taskId),
- /* menuWidth= */ menuWidth,
/* showImmersiveOption= */
DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()
&& TaskInfoKt.getRequestingImmersive(mTaskInfo),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt
index b21c3f522eab..458815d19658 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt
@@ -17,9 +17,12 @@
package com.android.wm.shell.windowdecor
import android.animation.ValueAnimator
+import android.annotation.DimenRes
+import android.content.res.Resources;
import android.content.Context
import android.util.AttributeSet
import android.widget.ImageButton
+import com.android.wm.shell.R
/**
* [ImageButton] for the handle at the top of fullscreen apps. Has custom hover
@@ -30,13 +33,23 @@ class HandleImageButton (context: Context?, attrs: AttributeSet?) :
ImageButton(context, attrs) {
private val handleAnimator = ValueAnimator()
+ /** Final horizontal padding for hover enter. **/
+ private val HANDLE_HOVER_ENTER_PADDING = loadDimensionPixelSize(
+ R.dimen.desktop_mode_fullscreen_decor_caption_horizontal_padding_hovered)
+ /** Final horizontal padding for press down. **/
+ private val HANDLE_PRESS_DOWN_PADDING = loadDimensionPixelSize(
+ R.dimen.desktop_mode_fullscreen_decor_caption_horizontal_padding_touched)
+ /** Default horizontal padding. **/
+ private val HANDLE_DEFAULT_PADDING = loadDimensionPixelSize(
+ R.dimen.desktop_mode_fullscreen_decor_caption_horizontal_padding_default)
+
override fun onHoverChanged(hovered: Boolean) {
super.onHoverChanged(hovered)
if (hovered) {
- animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_HOVER_ENTER_SCALE)
+ animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_HOVER_ENTER_PADDING)
} else {
if (!isPressed) {
- animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_DEFAULT_SCALE)
+ animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_DEFAULT_PADDING)
}
}
}
@@ -45,35 +58,37 @@ class HandleImageButton (context: Context?, attrs: AttributeSet?) :
if (isPressed != pressed) {
super.setPressed(pressed)
if (pressed) {
- animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_PRESS_DOWN_SCALE)
+ animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_PRESS_DOWN_PADDING)
} else {
- animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_DEFAULT_SCALE)
+ animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_DEFAULT_PADDING)
}
}
}
- private fun animateHandle(duration: Long, endScale: Float) {
+ private fun animateHandle(duration: Long, endPadding: Int) {
if (handleAnimator.isRunning) {
handleAnimator.cancel()
}
handleAnimator.duration = duration
- handleAnimator.setFloatValues(scaleX, endScale)
+ handleAnimator.setIntValues(paddingLeft, endPadding)
handleAnimator.addUpdateListener { animator ->
- scaleX = animator.animatedValue as Float
+ val padding = animator.animatedValue as Int
+ setPadding(padding, paddingTop, padding, paddingBottom)
}
handleAnimator.start()
}
+ private fun loadDimensionPixelSize(@DimenRes resourceId: Int): Int {
+ if (resourceId == Resources.ID_NULL) {
+ return 0
+ }
+ return context.resources.getDimensionPixelSize(resourceId)
+ }
+
companion object {
/** The duration of animations related to hover state. **/
private const val HANDLE_HOVER_ANIM_DURATION = 300L
/** The duration of animations related to pressed state. **/
private const val HANDLE_PRESS_ANIM_DURATION = 200L
- /** Ending scale for hover enter. **/
- private const val HANDLE_HOVER_ENTER_SCALE = 1.2f
- /** Ending scale for press down. **/
- private const val HANDLE_PRESS_DOWN_SCALE = 0.85f
- /** Default scale for handle. **/
- private const val HANDLE_DEFAULT_SCALE = 1f
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
index 38accce82999..ad3525af3f94 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
@@ -90,7 +90,7 @@ class MaximizeMenu(
private val displayController: DisplayController,
private val taskInfo: RunningTaskInfo,
private val decorWindowContext: Context,
- private val menuPosition: PointF,
+ private val positionSupplier: (Int, Int) -> PointF,
private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() }
) {
private var maximizeMenu: AdditionalViewHostViewContainer? = null
@@ -100,19 +100,19 @@ class MaximizeMenu(
private val cornerRadius = loadDimensionPixelSize(
R.dimen.desktop_mode_maximize_menu_corner_radius
).toFloat()
- private val menuHeight = loadDimensionPixelSize(R.dimen.desktop_mode_maximize_menu_height)
+ private lateinit var menuPosition: PointF
private val menuPadding = loadDimensionPixelSize(R.dimen.desktop_mode_menu_padding)
/** Position the menu relative to the caption's position. */
- fun positionMenu(position: PointF, t: Transaction) {
- menuPosition.set(position)
+ fun positionMenu(t: Transaction) {
+ menuPosition = positionSupplier(maximizeMenuView?.measureWidth() ?: 0,
+ maximizeMenuView?.measureHeight() ?: 0)
t.setPosition(leash, menuPosition.x, menuPosition.y)
}
/** Creates and shows the maximize window. */
fun show(
isTaskInImmersiveMode: Boolean,
- menuWidth: Int,
showImmersiveOption: Boolean,
showSnapOptions: Boolean,
onMaximizeOrRestoreClickListener: () -> Unit,
@@ -125,7 +125,6 @@ class MaximizeMenu(
if (maximizeMenu != null) return
createMaximizeMenu(
isTaskInImmersiveMode = isTaskInImmersiveMode,
- menuWidth = menuWidth,
showImmersiveOption = showImmersiveOption,
showSnapOptions = showSnapOptions,
onMaximizeClickListener = onMaximizeOrRestoreClickListener,
@@ -161,7 +160,6 @@ class MaximizeMenu(
/** Create a maximize menu that is attached to the display area. */
private fun createMaximizeMenu(
isTaskInImmersiveMode: Boolean,
- menuWidth: Int,
showImmersiveOption: Boolean,
showSnapOptions: Boolean,
onMaximizeClickListener: () -> Unit,
@@ -178,16 +176,6 @@ class MaximizeMenu(
.setName("Maximize Menu")
.setContainerLayer()
.build()
- val lp = WindowManager.LayoutParams(
- menuWidth,
- menuHeight,
- WindowManager.LayoutParams.TYPE_APPLICATION,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
- PixelFormat.TRANSPARENT
- )
- lp.title = "Maximize Menu for Task=" + taskInfo.taskId
- lp.setTrustedOverlay()
val windowManager = WindowlessWindowManager(
taskInfo.configuration,
leash,
@@ -207,7 +195,6 @@ class MaximizeMenu(
MaximizeMenuView.ImmersiveConfig.Hidden
},
showSnapOptions = showSnapOptions,
- menuHeight = menuHeight,
menuPadding = menuPadding,
).also { menuView ->
menuView.bind(taskInfo)
@@ -217,6 +204,19 @@ class MaximizeMenu(
menuView.onRightSnapClickListener = onRightSnapClickListener
menuView.onMenuHoverListener = onHoverListener
menuView.onOutsideTouchListener = onOutsideTouchListener
+ val menuWidth = menuView.measureWidth()
+ val menuHeight = menuView.measureHeight()
+ menuPosition = positionSupplier(menuWidth, menuHeight)
+ val lp = WindowManager.LayoutParams(
+ menuWidth.toInt(),
+ menuHeight.toInt(),
+ WindowManager.LayoutParams.TYPE_APPLICATION,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
+ PixelFormat.TRANSPARENT
+ )
+ lp.title = "Maximize Menu for Task=" + taskInfo.taskId
+ lp.setTrustedOverlay()
viewHost.setView(menuView.rootView, lp)
}
@@ -268,7 +268,6 @@ class MaximizeMenu(
private val sizeToggleDirection: SizeToggleDirection,
immersiveConfig: ImmersiveConfig,
showSnapOptions: Boolean,
- private val menuHeight: Int,
private val menuPadding: Int
) {
val rootView = LayoutInflater.from(context)
@@ -583,7 +582,7 @@ class MaximizeMenu(
// the menu.
val value = animatedValue as Float
val topPadding = menuPadding -
- ((1 - value) * menuHeight).toInt()
+ ((1 - value) * measureHeight()).toInt()
container.setPadding(menuPadding, topPadding,
menuPadding, menuPadding)
}
@@ -604,7 +603,7 @@ class MaximizeMenu(
}
},
ObjectAnimator.ofFloat(rootView, TRANSLATION_Y,
- (STARTING_MENU_HEIGHT_SCALE - 1) * menuHeight, 0f).apply {
+ (STARTING_MENU_HEIGHT_SCALE - 1) * measureHeight(), 0f).apply {
duration = OPEN_MENU_HEIGHT_ANIMATION_DURATION_MS
interpolator = EMPHASIZED_DECELERATE
},
@@ -667,7 +666,7 @@ class MaximizeMenu(
// the menu.
val value = animatedValue as Float
val topPadding = menuPadding -
- ((1 - value) * menuHeight).toInt()
+ ((1 - value) * measureHeight()).toInt()
container.setPadding(menuPadding, topPadding,
menuPadding, menuPadding)
}
@@ -688,7 +687,7 @@ class MaximizeMenu(
}
},
ObjectAnimator.ofFloat(rootView, TRANSLATION_Y,
- 0f, (STARTING_MENU_HEIGHT_SCALE - 1) * menuHeight).apply {
+ 0f, (STARTING_MENU_HEIGHT_SCALE - 1) * measureHeight()).apply {
duration = CLOSE_MENU_HEIGHT_ANIMATION_DURATION_MS
interpolator = FAST_OUT_LINEAR_IN
},
@@ -792,6 +791,18 @@ class MaximizeMenu(
)
}
+ /** Measure width of the root view of this menu. */
+ fun measureWidth() : Int {
+ rootView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ return rootView.getMeasuredWidth()
+ }
+
+ /** Measure height of the root view of this menu. */
+ fun measureHeight() : Int {
+ rootView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ return rootView.getMeasuredHeight()
+ }
+
private fun deactivateSnapOptions() {
// TODO(b/346440693): the background/colorStateList set on these buttons is overridden
// to a static resource & color on manually tracked hover events, which defeats the
@@ -1036,7 +1047,7 @@ interface MaximizeMenuFactory {
displayController: DisplayController,
taskInfo: RunningTaskInfo,
decorWindowContext: Context,
- menuPosition: PointF,
+ positionSupplier: (Int, Int) -> PointF,
transactionSupplier: Supplier<Transaction>
): MaximizeMenu
}
@@ -1049,7 +1060,7 @@ object DefaultMaximizeMenuFactory : MaximizeMenuFactory {
displayController: DisplayController,
taskInfo: RunningTaskInfo,
decorWindowContext: Context,
- menuPosition: PointF,
+ positionSupplier: (Int, Int) -> PointF,
transactionSupplier: Supplier<Transaction>
): MaximizeMenu {
return MaximizeMenu(
@@ -1058,7 +1069,7 @@ object DefaultMaximizeMenuFactory : MaximizeMenuFactory {
displayController,
taskInfo,
decorWindowContext,
- menuPosition,
+ positionSupplier,
transactionSupplier
)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
index a9c2e68e62a6..bb20292a51d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt
@@ -237,8 +237,12 @@ class MultiDisplayVeiledResizeTaskPositioner(
val startDisplayLayout = displayController.getDisplayLayout(startDisplayId)
val currentDisplayLayout = displayController.getDisplayLayout(displayId)
- if (startDisplayLayout == null || currentDisplayLayout == null) {
- // Fall back to single-display drag behavior if any display layout is unavailable.
+ if (startDisplayId == displayId
+ || startDisplayLayout == null || currentDisplayLayout == null) {
+ // Fall back to single-display drag behavior if:
+ // 1. The drag destination display is the same as the start display. This prevents
+ // unnecessary animations caused by minor width/height changes due to DPI scaling.
+ // 2. Either the starting or current display layout is unavailable.
DragPositioningCallbackUtility.updateTaskBounds(
repositionTaskBounds,
taskBoundsAtDragStart,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java
index bc85d2b40748..45ba4413814c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java
@@ -86,14 +86,18 @@ class TaskOperations {
return null;
}
- IBinder minimizeTask(WindowContainerToken taskToken) {
- return minimizeTask(taskToken, new WindowContainerTransaction());
+ IBinder minimizeTask(WindowContainerToken taskToken, int taskId, boolean isLastTask) {
+ return minimizeTask(taskToken, taskId, isLastTask, new WindowContainerTransaction());
}
- IBinder minimizeTask(WindowContainerToken taskToken, WindowContainerTransaction wct) {
+ IBinder minimizeTask(
+ WindowContainerToken taskToken,
+ int taskId,
+ boolean isLastTask,
+ WindowContainerTransaction wct) {
wct.reorder(taskToken, false);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- return mTransitionStarter.startMinimizedModeTransition(wct);
+ return mTransitionStarter.startMinimizedModeTransition(wct, taskId, isLastTask);
} else {
mSyncQueue.queue(wct);
return null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 76005c22972a..4002dc572897 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -361,6 +361,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
}
outResult.mRootView = rootView;
+ final boolean fontScaleChanged = mWindowDecorConfig != null
+ && mWindowDecorConfig.fontScale != mTaskInfo.configuration.fontScale;
final int oldDensityDpi = mWindowDecorConfig != null
? mWindowDecorConfig.densityDpi : DENSITY_DPI_UNDEFINED;
final int oldNightMode = mWindowDecorConfig != null
@@ -375,7 +377,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|| mDisplay.getDisplayId() != mTaskInfo.displayId
|| oldLayoutResId != mLayoutResId
|| oldNightMode != newNightMode
- || mDecorWindowContext == null) {
+ || mDecorWindowContext == null
+ || fontScaleChanged) {
releaseViews(wct);
if (!obtainDisplayOrRegisterListener()) {
@@ -911,7 +914,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
}
}
- @VisibleForTesting
public interface SurfaceControlViewHostFactory {
default SurfaceControlViewHost create(Context c, Display d, WindowlessWindowManager wmm) {
return new SurfaceControlViewHost(c, d, wmm, "WindowDecoration");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt
index 4a09614029dc..a5592f81a39e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt
@@ -50,9 +50,8 @@ class ReusableWindowDecorViewHost(
@VisibleForTesting
val viewHostAdapter: SurfaceControlViewHostAdapter =
SurfaceControlViewHostAdapter(context, display),
+ private val rootView: FrameLayout = FrameLayout(context)
) : WindowDecorViewHost, Warmable {
- @VisibleForTesting val rootView = FrameLayout(context)
-
private var currentUpdateJob: Job? = null
override val surfaceControl: SurfaceControl
@@ -131,8 +130,10 @@ class ReusableWindowDecorViewHost(
Trace.beginSection("ReusableWindowDecorViewHost#updateViewHost")
viewHostAdapter.prepareViewHost(configuration, touchableRegion)
onDrawTransaction?.let { viewHostAdapter.applyTransactionOnDraw(it) }
- rootView.removeAllViews()
- rootView.addView(view)
+ if (view.parent != rootView) {
+ rootView.removeAllViews()
+ rootView.addView(view)
+ }
viewHostAdapter.updateView(rootView, attrs)
Trace.endSection()
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/SnapEventHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/SnapEventHandler.kt
new file mode 100644
index 000000000000..52e24d6fe0d0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/SnapEventHandler.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.windowdecor.tiling
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.graphics.Rect
+import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
+
+/** Interface for handling snap to half screen events. */
+interface SnapEventHandler {
+ /** Snaps an app to half the screen for tiling. */
+ fun snapToHalfScreen(
+ taskInfo: RunningTaskInfo,
+ currentDragBounds: Rect,
+ position: SnapPosition,
+ ): Boolean
+
+ /** Removes a task from tiling if it's tiled, for example on task exiting. */
+ fun removeTaskIfTiled(displayId: Int, taskId: Int)
+
+ /** Notifies the tiling handler of user switch. */
+ fun onUserChange()
+
+ /** Notifies the tiling handler of overview animation state change. */
+ fun onOverviewAnimationStateChange(running: Boolean)
+
+ /** If a task is tiled, delegate moving to front to tiling infrastructure. */
+ fun moveTaskToFrontIfTiled(taskInfo: RunningTaskInfo): Boolean
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index bf5e374c7607..bff12d026b93 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -45,6 +45,7 @@ android_test {
"androidx.test.rules",
"androidx.test.ext.junit",
"androidx.datastore_datastore",
+ "androidx.core_core-animation-testing",
"kotlinx_coroutines_test",
"androidx.dynamicanimation_dynamicanimation",
"dagger2",
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java
index 4198f5904566..42310caba1c6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java
@@ -17,6 +17,10 @@ package com.android.wm.shell.bubbles;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -31,12 +35,14 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.graphics.Rect;
import android.os.IBinder;
import android.view.SurfaceControl;
import android.view.ViewRootImpl;
import android.window.IWindowContainerToken;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
@@ -65,6 +71,10 @@ import org.mockito.MockitoAnnotations;
*/
@SmallTest
public class BubbleTransitionsTest extends ShellTestCase {
+
+ private static final int FULLSCREEN_TASK_WIDTH = 200;
+ private static final int FULLSCREEN_TASK_HEIGHT = 100;
+
@Mock
private BubbleData mBubbleData;
@Mock
@@ -117,10 +127,7 @@ public class BubbleTransitionsTest extends ShellTestCase {
private ActivityManager.RunningTaskInfo setupBubble() {
ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
- final IWindowContainerToken itoken = mock(IWindowContainerToken.class);
- final IBinder asBinder = mock(IBinder.class);
- when(itoken.asBinder()).thenReturn(asBinder);
- WindowContainerToken token = new WindowContainerToken(itoken);
+ WindowContainerToken token = createMockToken();
taskInfo.token = token;
final TaskView tv = mock(TaskView.class);
final TaskViewTaskController tvtc = mock(TaskViewTaskController.class);
@@ -131,13 +138,32 @@ public class BubbleTransitionsTest extends ShellTestCase {
return taskInfo;
}
+ private TransitionInfo setupFullscreenTaskTransition(ActivityManager.RunningTaskInfo taskInfo) {
+ final TransitionInfo info = new TransitionInfo(TRANSIT_CONVERT_TO_BUBBLE, 0);
+ final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token,
+ mock(SurfaceControl.class));
+ chg.setTaskInfo(taskInfo);
+ chg.setMode(TRANSIT_CHANGE);
+ chg.setStartAbsBounds(new Rect(0, 0, FULLSCREEN_TASK_WIDTH, FULLSCREEN_TASK_HEIGHT));
+ info.addChange(chg);
+ info.addRoot(new TransitionInfo.Root(0, mock(SurfaceControl.class), 0, 0));
+ return info;
+ }
+
+ private WindowContainerToken createMockToken() {
+ final IWindowContainerToken itoken = mock(IWindowContainerToken.class);
+ final IBinder asBinder = mock(IBinder.class);
+ when(itoken.asBinder()).thenReturn(asBinder);
+ return new WindowContainerToken(itoken);
+ }
+
@Test
public void testConvertToBubble() {
// Basic walk-through of convert-to-bubble transition stages
ActivityManager.RunningTaskInfo taskInfo = setupBubble();
final BubbleTransitions.BubbleTransition bt = mBubbleTransitions.startConvertToBubble(
mBubble, taskInfo, mExpandedViewManager, mTaskViewFactory, mBubblePositioner,
- mStackView, mLayerView, mIconFactory, false);
+ mStackView, mLayerView, mIconFactory, null, false);
final BubbleTransitions.ConvertToBubble ctb = (BubbleTransitions.ConvertToBubble) bt;
ctb.onInflated(mBubble);
when(mLayerView.canExpandView(any())).thenReturn(true);
@@ -146,13 +172,7 @@ public class BubbleTransitionsTest extends ShellTestCase {
// Ensure we are communicating with the taskviewtransitions queue
assertTrue(mTaskViewTransitions.hasPending());
- final TransitionInfo info = new TransitionInfo(TRANSIT_CHANGE, 0);
- final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token,
- mock(SurfaceControl.class));
- chg.setTaskInfo(taskInfo);
- chg.setMode(TRANSIT_CHANGE);
- info.addChange(chg);
- info.addRoot(new TransitionInfo.Root(0, mock(SurfaceControl.class), 0, 0));
+ final TransitionInfo info = setupFullscreenTaskTransition(taskInfo);
SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
final boolean[] finishCalled = new boolean[]{false};
@@ -163,22 +183,69 @@ public class BubbleTransitionsTest extends ShellTestCase {
ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb);
assertFalse(mTaskViewTransitions.hasPending());
+ verify(startT).setPosition(any(), eq(0f), eq(0f));
+
verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean());
- ctb.continueExpand();
clearInvocations(mBubble);
verify(mBubble, never()).setPreparingTransition(any());
ctb.surfaceCreated();
- verify(mBubble).setPreparingTransition(isNull());
+ // Check that preparing transition is not reset before continueExpand is called
+ verify(mBubble, never()).setPreparingTransition(any());
ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class);
verify(mLayerView).animateConvert(any(), any(), any(), any(), animCb.capture());
+
+ // continueExpand is now called, check that preparing transition is cleared
+ ctb.continueExpand();
+ verify(mBubble).setPreparingTransition(isNull());
+
assertFalse(finishCalled[0]);
animCb.getValue().run();
assertTrue(finishCalled[0]);
}
@Test
+ public void testConvertToBubble_drag() {
+ ActivityManager.RunningTaskInfo taskInfo = setupBubble();
+
+ Rect draggedTaskBounds = new Rect(10, 20, 30, 40);
+ WindowContainerTransaction pendingWct = new WindowContainerTransaction();
+ WindowContainerToken pendingDragOpToken = createMockToken();
+ pendingWct.reorder(pendingDragOpToken, /* onTop= */ false);
+
+ BubbleTransitions.DragData dragData = new BubbleTransitions.DragData(
+ draggedTaskBounds, pendingWct, /* releasedOnLeft= */ false
+ );
+
+ final BubbleTransitions.BubbleTransition bt = mBubbleTransitions.startConvertToBubble(
+ mBubble, taskInfo, mExpandedViewManager, mTaskViewFactory, mBubblePositioner,
+ mStackView, mLayerView, mIconFactory, dragData, false);
+ final BubbleTransitions.ConvertToBubble ctb = (BubbleTransitions.ConvertToBubble) bt;
+
+ ArgumentCaptor<WindowContainerTransaction> wctCaptor = ArgumentCaptor.forClass(
+ WindowContainerTransaction.class);
+ ctb.onInflated(mBubble);
+ verify(mTransitions).startTransition(anyInt(), wctCaptor.capture(), eq(ctb));
+
+ // Verify that the WCT has the pending operation from drag data
+ WindowContainerTransaction transitionWct = wctCaptor.getValue();
+ assertThat(transitionWct.getHierarchyOps().stream().anyMatch(op -> op.getType()
+ == WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
+ && op.getContainer() == pendingDragOpToken.asBinder())).isTrue();
+
+ final TransitionInfo info = setupFullscreenTaskTransition(taskInfo);
+ SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
+ Transitions.TransitionFinishCallback finishCb = wct -> {};
+ ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb);
+
+ // Verify that dragged task bounds are used for the position
+ verify(startT).setPosition(any(), eq((float) draggedTaskBounds.left),
+ eq((float) draggedTaskBounds.top));
+ }
+
+ @Test
public void testConvertFromBubble() {
ActivityManager.RunningTaskInfo taskInfo = setupBubble();
final BubbleTransitions.BubbleTransition bt = mBubbleTransitions.startConvertFromBubble(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java
index d3de0f7c09b4..3d5e9495e29d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayControllerTests.java
@@ -16,26 +16,52 @@
package com.android.wm.shell.common;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
-import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.RectF;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayTopology;
+import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
+import android.testing.TestableContext;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayAdjustments;
+import android.view.IDisplayWindowListener;
import android.view.IWindowManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestSyncExecutor;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.sysui.ShellInit;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.quality.Strictness;
+
+import java.util.function.Consumer;
/**
* Tests for the display controller.
@@ -46,23 +72,163 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DisplayControllerTests extends ShellTestCase {
-
- private @Mock Context mContext;
- private @Mock IWindowManager mWM;
- private @Mock ShellInit mShellInit;
- private @Mock ShellExecutor mMainExecutor;
- private @Mock DisplayManager mDisplayManager;
+ @Mock private IWindowManager mWM;
+ @Mock private ShellInit mShellInit;
+ @Mock private DisplayManager mDisplayManager;
+ @Mock private DisplayTopology mMockTopology;
+ @Mock private DisplayController.OnDisplaysChangedListener mListener;
+ private StaticMockitoSession mMockitoSession;
+ private TestSyncExecutor mMainExecutor;
+ private IDisplayWindowListener mDisplayContainerListener;
+ private Consumer<DisplayTopology> mCapturedTopologyListener;
+ private Display mMockDisplay;
private DisplayController mController;
+ private static final int DISPLAY_ID_0 = 0;
+ private static final int DISPLAY_ID_1 = 1;
+ private static final RectF DISPLAY_ABS_BOUNDS_0 = new RectF(10, 10, 20, 20);
+ private static final RectF DISPLAY_ABS_BOUNDS_1 = new RectF(11, 11, 22, 22);
@Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
+ public void setUp() throws RemoteException {
+ mMockitoSession =
+ ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .mockStatic(DesktopModeStatus.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ mContext = spy(new TestableContext(
+ androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
+ .getContext(), null));
+
+ mMainExecutor = new TestSyncExecutor();
mController = new DisplayController(
mContext, mWM, mShellInit, mMainExecutor, mDisplayManager);
+
+ mMockDisplay = mock(Display.class);
+ when(mMockDisplay.getDisplayAdjustments()).thenReturn(
+ new DisplayAdjustments(new Configuration()));
+ when(mDisplayManager.getDisplay(anyInt())).thenReturn(mMockDisplay);
+ when(mDisplayManager.getDisplayTopology()).thenReturn(mMockTopology);
+ doAnswer(invocation -> {
+ mDisplayContainerListener = invocation.getArgument(0);
+ return new int[]{DISPLAY_ID_0};
+ }).when(mWM).registerDisplayWindowListener(any());
+ doAnswer(invocation -> {
+ mCapturedTopologyListener = invocation.getArgument(1);
+ return null;
+ }).when(mDisplayManager).registerTopologyListener(any(), any());
+ SparseArray<RectF> absoluteBounds = new SparseArray<>();
+ absoluteBounds.put(DISPLAY_ID_0, DISPLAY_ABS_BOUNDS_0);
+ absoluteBounds.put(DISPLAY_ID_1, DISPLAY_ABS_BOUNDS_1);
+ when(mMockTopology.getAbsoluteBounds()).thenReturn(absoluteBounds);
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockitoSession != null) {
+ mMockitoSession.finishMocking();
+ }
}
@Test
public void instantiateController_addInitCallback() {
verify(mShellInit, times(1)).addInitCallback(any(), eq(mController));
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG)
+ public void onInit_canEnterDesktopMode_registerListeners() throws RemoteException {
+ ExtendedMockito.doReturn(true)
+ .when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
+
+ mController.onInit();
+
+ assertNotNull(mController.getDisplayContext(DISPLAY_ID_0));
+ verify(mWM).registerDisplayWindowListener(any());
+ verify(mDisplayManager).registerTopologyListener(eq(mMainExecutor), any());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG)
+ public void onInit_canNotEnterDesktopMode_onlyRegisterDisplayWindowListener()
+ throws RemoteException {
+ ExtendedMockito.doReturn(false)
+ .when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
+
+ mController.onInit();
+
+ assertNotNull(mController.getDisplayContext(DISPLAY_ID_0));
+ verify(mWM).registerDisplayWindowListener(any());
+ verify(mDisplayManager, never()).registerTopologyListener(any(), any());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG)
+ public void addDisplayWindowListener_notifiesExistingDisplaysAndTopology() {
+ ExtendedMockito.doReturn(true)
+ .when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
+
+ mController.onInit();
+ mController.addDisplayWindowListener(mListener);
+
+ verify(mListener).onDisplayAdded(eq(DISPLAY_ID_0));
+ verify(mListener).onTopologyChanged(eq(mMockTopology));
+ }
+
+ @Test
+ public void onDisplayAddedAndRemoved_updatesDisplayContexts() throws RemoteException {
+ mController.onInit();
+ mController.addDisplayWindowListener(mListener);
+
+ mDisplayContainerListener.onDisplayAdded(DISPLAY_ID_1);
+
+ verify(mListener).onDisplayAdded(eq(DISPLAY_ID_0));
+ verify(mListener).onDisplayAdded(eq(DISPLAY_ID_1));
+ assertNotNull(mController.getDisplayContext(DISPLAY_ID_1));
+ verify(mContext).createDisplayContext(eq(mMockDisplay));
+
+ mDisplayContainerListener.onDisplayRemoved(DISPLAY_ID_1);
+
+ assertNull(mController.getDisplayContext(DISPLAY_ID_1));
+ verify(mListener).onDisplayRemoved(eq(DISPLAY_ID_1));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG)
+ public void onDisplayTopologyChanged_updateDisplayLayout() throws RemoteException {
+ ExtendedMockito.doReturn(true)
+ .when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
+ mController.onInit();
+ mController.addDisplayWindowListener(mListener);
+ mDisplayContainerListener.onDisplayAdded(DISPLAY_ID_1);
+
+ mCapturedTopologyListener.accept(mMockTopology);
+
+ assertEquals(DISPLAY_ABS_BOUNDS_0, mController.getDisplayLayout(DISPLAY_ID_0)
+ .globalBoundsDp());
+ assertEquals(DISPLAY_ABS_BOUNDS_1, mController.getDisplayLayout(DISPLAY_ID_1)
+ .globalBoundsDp());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG)
+ public void onDisplayTopologyChanged_topologyBeforeDisplayAdded_appliesBoundsOnAdd()
+ throws RemoteException {
+ ExtendedMockito.doReturn(true)
+ .when(() -> DesktopModeStatus.canEnterDesktopMode(any()));
+ mController.onInit();
+ mController.addDisplayWindowListener(mListener);
+
+ mCapturedTopologyListener.accept(mMockTopology);
+
+ assertNull(mController.getDisplayLayout(DISPLAY_ID_1));
+
+ mDisplayContainerListener.onDisplayAdded(DISPLAY_ID_1);
+
+ assertEquals(DISPLAY_ABS_BOUNDS_0,
+ mController.getDisplayLayout(DISPLAY_ID_0).globalBoundsDp());
+ assertEquals(DISPLAY_ABS_BOUNDS_1,
+ mController.getDisplayLayout(DISPLAY_ID_1).globalBoundsDp());
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/WindowContainerTransactionSupplierTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/WindowContainerTransactionSupplierTest.kt
new file mode 100644
index 000000000000..c91ef5e6b868
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/WindowContainerTransactionSupplierTest.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2025 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.wm.shell.common
+
+import android.testing.AndroidTestingRunner
+import android.window.WindowContainerTransaction
+import androidx.test.filters.SmallTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for [WindowContainerTransactionSupplier].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:WindowContainerTransactionSupplierTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class WindowContainerTransactionSupplierTest {
+
+ @Test
+ fun `WindowContainerTransactionSupplier supplies a WindowContainerTransaction`() {
+ val supplier = WindowContainerTransactionSupplier()
+ SuppliersUtilsTest.assertSupplierProvidesValue(supplier) {
+ it is WindowContainerTransaction
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithmTest.java
index e3798e92c092..a6c35f1bd93c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithmTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip.phone;
+package com.android.wm.shell.common.pip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -29,9 +29,6 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.pip.PhonePipKeepClearAlgorithm;
-import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
-import com.android.wm.shell.common.pip.PipBoundsState;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhoneSizeSpecSourceTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PhoneSizeSpecSourceTest.java
index 85f1da5322ea..737735c9efcd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhoneSizeSpecSourceTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PhoneSizeSpecSourceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip.phone;
+package com.android.wm.shell.common.pip;
import static org.mockito.Mockito.when;
@@ -27,9 +27,6 @@ import android.view.DisplayInfo;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
-import com.android.wm.shell.common.pip.PipDisplayLayoutState;
-import com.android.wm.shell.common.pip.SizeSpecSource;
import org.junit.Assert;
import org.junit.Before;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsAlgorithmTest.java
index 080b0ae006ea..6bda2259b44c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsAlgorithmTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip;
+package com.android.wm.shell.common.pip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -32,13 +32,6 @@ import androidx.test.filters.SmallTest;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
-import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
-import com.android.wm.shell.common.pip.PipBoundsState;
-import com.android.wm.shell.common.pip.PipDisplayLayoutState;
-import com.android.wm.shell.common.pip.PipKeepClearAlgorithmInterface;
-import com.android.wm.shell.common.pip.PipSnapAlgorithm;
-import com.android.wm.shell.common.pip.SizeSpecSource;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsStateTest.java
index 304da75f870c..ad664acfdc37 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipBoundsStateTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip;
+package com.android.wm.shell.common.pip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -36,10 +36,6 @@ import androidx.test.filters.SmallTest;
import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
-import com.android.wm.shell.common.pip.PipBoundsState;
-import com.android.wm.shell.common.pip.PipDisplayLayoutState;
-import com.android.wm.shell.common.pip.SizeSpecSource;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDoubleTapHelperTest.java
index b583acda1c9a..1756aad8fc9b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDoubleTapHelperTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip.phone;
+package com.android.wm.shell.common.pip;
import static com.android.wm.shell.common.pip.PipDoubleTapHelper.SIZE_SPEC_CUSTOM;
import static com.android.wm.shell.common.pip.PipDoubleTapHelper.SIZE_SPEC_DEFAULT;
@@ -29,8 +29,6 @@ import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.pip.PipBoundsState;
-import com.android.wm.shell.common.pip.PipDoubleTapHelper;
import org.junit.Assert;
import org.junit.Before;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipSnapAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipSnapAlgorithmTest.java
index ac13d7ffcd61..3e71ab3e1ad4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipSnapAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipSnapAlgorithmTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip;
+package com.android.wm.shell.common.pip;
import static org.junit.Assert.assertEquals;
@@ -25,8 +25,6 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.pip.PipBoundsState;
-import com.android.wm.shell.common.pip.PipSnapAlgorithm;
import org.junit.Before;
import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/FlexParallaxSpecTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/FlexParallaxSpecTests.java
new file mode 100644
index 000000000000..22a85fc49a4b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/FlexParallaxSpecTests.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.common.split;
+
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+
+import static com.android.wm.shell.common.split.ResizingEffectPolicy.DEFAULT_OFFSCREEN_DIM;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.wm.shell.common.split.DividerSnapAlgorithm.SnapTarget;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class FlexParallaxSpecTests {
+ ParallaxSpec mFlexSpec = new FlexParallaxSpec();
+
+ Rect mDisplayBounds = new Rect(0, 0, 1000, 1000);
+ Rect mRetreatingSurface = new Rect(0, 0, 1000, 1000);
+ Rect mRetreatingContent = new Rect(0, 0, 1000, 1000);
+ Rect mAdvancingSurface = new Rect(0, 0, 1000, 1000);
+ Rect mAdvancingContent = new Rect(0, 0, 1000, 1000);
+ boolean mIsLeftRightSplit;
+ boolean mTopLeftShrink;
+
+ int mDimmingSide;
+ float mDimValue;
+ Point mRetreatingParallax = new Point(0, 0);
+ Point mAdvancingParallax = new Point(0, 0);
+
+ @Mock DividerSnapAlgorithm mockSnapAlgorithm;
+ @Mock SnapTarget mockStartEdge;
+ @Mock SnapTarget mockFirstTarget;
+ @Mock SnapTarget mockMiddleTarget;
+ @Mock SnapTarget mockLastTarget;
+ @Mock SnapTarget mockEndEdge;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mockSnapAlgorithm.getDismissStartTarget()).thenReturn(mockStartEdge);
+ when(mockSnapAlgorithm.getFirstSplitTarget()).thenReturn(mockFirstTarget);
+ when(mockSnapAlgorithm.getMiddleTarget()).thenReturn(mockMiddleTarget);
+ when(mockSnapAlgorithm.getLastSplitTarget()).thenReturn(mockLastTarget);
+ when(mockSnapAlgorithm.getDismissEndTarget()).thenReturn(mockEndEdge);
+
+ when(mockStartEdge.getPosition()).thenReturn(0);
+ when(mockFirstTarget.getPosition()).thenReturn(250);
+ when(mockMiddleTarget.getPosition()).thenReturn(500);
+ when(mockLastTarget.getPosition()).thenReturn(750);
+ when(mockEndEdge.getPosition()).thenReturn(1000);
+ }
+
+ @Test
+ public void testHorizontalDragFromCenter() {
+ mIsLeftRightSplit = true;
+ simulateDragFromCenterToLeft(125);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_LEFT);
+ assertThat(mDimValue).isGreaterThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mDimValue).isLessThan(1f);
+ assertThat(mRetreatingParallax.x).isGreaterThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromCenterToLeft(250);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_LEFT);
+ assertThat(mDimValue).isEqualTo(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isGreaterThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromCenterToLeft(375);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_LEFT);
+ assertThat(mDimValue).isGreaterThan(0f);
+ assertThat(mDimValue).isLessThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isGreaterThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromCenterToRight(500);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_INVALID);
+ assertThat(mDimValue).isEqualTo(0f);
+ assertThat(mRetreatingParallax.x).isEqualTo(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromCenterToRight(625);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_RIGHT);
+ assertThat(mDimValue).isGreaterThan(0f);
+ assertThat(mDimValue).isLessThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isEqualTo(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromCenterToRight(750);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_RIGHT);
+ assertThat(mDimValue).isEqualTo(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isEqualTo(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromCenterToRight(875);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_RIGHT);
+ assertThat(mDimValue).isGreaterThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mDimValue).isLessThan(1f);
+ assertThat(mRetreatingParallax.x).isEqualTo(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+ }
+
+ @Test
+ public void testHorizontalDragFromLeft() {
+ mIsLeftRightSplit = true;
+ simulateDragFromLeftToLeft(125);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_LEFT);
+ assertThat(mDimValue).isGreaterThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mDimValue).isLessThan(1f);
+ assertThat(mRetreatingParallax.x).isGreaterThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromLeftToLeft(250);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_LEFT);
+ assertThat(mDimValue).isEqualTo(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isEqualTo(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromLeftToCenter(375);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_LEFT);
+ assertThat(mDimValue).isGreaterThan(0f);
+ assertThat(mDimValue).isLessThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isLessThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromLeftToCenter(500);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_INVALID);
+ assertThat(mDimValue).isEqualTo(0f);
+ assertThat(mRetreatingParallax.x).isLessThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromLeftToRight(625);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_RIGHT);
+ assertThat(mDimValue).isGreaterThan(0f);
+ assertThat(mDimValue).isLessThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isLessThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromLeftToRight(750);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_RIGHT);
+ assertThat(mDimValue).isEqualTo(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isLessThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromLeftToRight(875);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_RIGHT);
+ assertThat(mDimValue).isGreaterThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mDimValue).isLessThan(1f);
+ assertThat(mRetreatingParallax.x).isLessThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isGreaterThan(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+ }
+
+ @Test
+ public void testHorizontalDragFromRight() {
+ mIsLeftRightSplit = true;
+
+ simulateDragFromRightToLeft(125);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_LEFT);
+ assertThat(mDimValue).isGreaterThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mDimValue).isLessThan(1f);
+ assertThat(mRetreatingParallax.x).isGreaterThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromRightToLeft(250);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_LEFT);
+ assertThat(mDimValue).isEqualTo(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isGreaterThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromRightToLeft(375);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_LEFT);
+ assertThat(mDimValue).isGreaterThan(0f);
+ assertThat(mDimValue).isLessThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isGreaterThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromRightToCenter(500);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_INVALID);
+ assertThat(mDimValue).isEqualTo(0f);
+ assertThat(mRetreatingParallax.x).isLessThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromRightToCenter(625);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_RIGHT);
+ assertThat(mDimValue).isGreaterThan(0f);
+ assertThat(mDimValue).isLessThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isLessThan(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromRightToRight(750);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_RIGHT);
+ assertThat(mDimValue).isEqualTo(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mRetreatingParallax.x).isEqualTo(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+
+ simulateDragFromRightToRight(875);
+ assertThat(mDimmingSide).isEqualTo(DOCKED_RIGHT);
+ assertThat(mDimValue).isGreaterThan(DEFAULT_OFFSCREEN_DIM);
+ assertThat(mDimValue).isLessThan(1f);
+ assertThat(mRetreatingParallax.x).isEqualTo(0);
+ assertThat(mRetreatingParallax.y).isEqualTo(0);
+ assertThat(mAdvancingParallax.x).isEqualTo(0);
+ assertThat(mAdvancingParallax.y).isEqualTo(0);
+ }
+
+ private void simulateDragFromCenterToLeft(int to) {
+ int from = 500;
+
+ mRetreatingSurface = flexOffscreenAppLeft(to);
+ mRetreatingContent = onscreenAppLeft(from);
+ mAdvancingSurface = onscreenAppRight(to);
+ mAdvancingContent = onscreenAppRight(from);
+
+ calculateDimAndParallax(from, to);
+ }
+
+ private void simulateDragFromCenterToRight(int to) {
+ int from = 500;
+
+ mRetreatingSurface = flexOffscreenAppRight(to);
+ mRetreatingContent = onscreenAppRight(from);
+ mAdvancingSurface = onscreenAppLeft(to);
+ mAdvancingContent = onscreenAppLeft(from);
+
+ calculateDimAndParallax(from, to);
+ }
+
+ private void simulateDragFromLeftToLeft(int to) {
+ int from = 250;
+
+ mRetreatingSurface = flexOffscreenAppLeft(to);
+ mRetreatingContent = fullOffscreenAppLeft(from);
+ mAdvancingSurface = onscreenAppRight(to);
+ mAdvancingContent = onscreenAppRight(from);
+
+ calculateDimAndParallax(from, to);
+ }
+
+ private void simulateDragFromLeftToCenter(int to) {
+ int from = 250;
+
+ mRetreatingSurface = onscreenAppRight(to);
+ mRetreatingContent = onscreenAppRight(from);
+ mAdvancingSurface = fullOffscreenAppLeft(to);
+ mAdvancingContent = fullOffscreenAppLeft(from);
+
+ calculateDimAndParallax(from, to);
+ }
+
+ private void simulateDragFromLeftToRight(int to) {
+ int from = 250;
+
+ mRetreatingSurface = flexOffscreenAppRight(to);
+ mRetreatingContent = onscreenAppRight(from);
+ mAdvancingSurface = fullOffscreenAppLeft(to);
+ mAdvancingContent = fullOffscreenAppLeft(from);
+
+ calculateDimAndParallax(from, to);
+ }
+
+ private void simulateDragFromRightToLeft(int to) {
+ int from = 750;
+
+ mRetreatingSurface = flexOffscreenAppLeft(to);
+ mRetreatingContent = onscreenAppLeft(from);
+ mAdvancingSurface = fullOffscreenAppRight(to);
+ mAdvancingContent = fullOffscreenAppRight(from);
+
+ calculateDimAndParallax(from, to);
+ }
+
+ private void simulateDragFromRightToCenter(int to) {
+ int from = 750;
+
+ mRetreatingSurface = onscreenAppLeft(to);
+ mRetreatingContent = onscreenAppLeft(from);
+ mAdvancingSurface = fullOffscreenAppRight(to);
+ mAdvancingContent = fullOffscreenAppRight(from);
+
+ calculateDimAndParallax(from, to);
+ }
+
+ private void simulateDragFromRightToRight(int to) {
+ int from = 750;
+
+ mRetreatingSurface = flexOffscreenAppRight(to);
+ mRetreatingContent = fullOffscreenAppRight(from);
+ mAdvancingSurface = onscreenAppLeft(to);
+ mAdvancingContent = onscreenAppLeft(from);
+
+ calculateDimAndParallax(from, to);
+ }
+
+ private Rect flexOffscreenAppLeft(int pos) {
+ return new Rect(pos - (1000 - pos), 0, pos, 1000);
+ }
+
+ private Rect onscreenAppLeft(int pos) {
+ return new Rect(0, 0, pos, 1000);
+ }
+
+ private Rect fullOffscreenAppLeft(int pos) {
+ return new Rect(Math.min(0, pos - 750), 0, pos, 1000);
+ }
+
+ private Rect flexOffscreenAppRight(int pos) {
+ return new Rect(pos, 0, pos * 2, 1000);
+ }
+
+ private Rect onscreenAppRight(int pos) {
+ return new Rect(pos, 0, 1000, 1000);
+ }
+
+ private Rect fullOffscreenAppRight(int pos) {
+ return new Rect(pos, 0, Math.max(pos + 750, 1000), 1000);
+ }
+
+ private void calculateDimAndParallax(int from, int to) {
+ resetParallax();
+ mTopLeftShrink = to < from;
+ mDimmingSide = mFlexSpec.getDimmingSide(to, mockSnapAlgorithm, mIsLeftRightSplit);
+ mDimValue = mFlexSpec.getDimValue(to, mockSnapAlgorithm);
+ mFlexSpec.getParallax(mRetreatingParallax, mAdvancingParallax, to, mockSnapAlgorithm,
+ mIsLeftRightSplit, mDisplayBounds, mRetreatingSurface, mRetreatingContent,
+ mAdvancingSurface, mAdvancingContent, mDimmingSide, mTopLeftShrink);
+ }
+
+ private void resetParallax() {
+ mRetreatingParallax.set(0, 0);
+ mAdvancingParallax.set(0, 0);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerFactoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerFactoryTest.kt
new file mode 100644
index 000000000000..a5f6ced20dc0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerFactoryTest.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2025 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.wm.shell.compatui.letterbox.events
+
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.window.WindowContainerToken
+import android.window.WindowContainerTransaction
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.WindowContainerTransactionSupplier
+import com.android.wm.shell.compatui.letterbox.LetterboxEvents.motionEventAt
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TRANSIT_MOVE_LETTERBOX_REACHABILITY
+import java.util.function.Consumer
+import kotlin.test.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+/**
+ * Tests for [ReachabilityGestureListenerFactory].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:ReachabilityGestureListenerFactoryTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ReachabilityGestureListenerFactoryTest : ShellTestCase() {
+
+ @Test
+ fun `When invoked a ReachabilityGestureListenerFactory is created`() {
+ runTestScenario { r ->
+ r.invokeCreate()
+
+ r.checkReachabilityGestureListenerCreated()
+ }
+ }
+
+ @Test
+ fun `Right parameters are used for creation`() {
+ runTestScenario { r ->
+ r.invokeCreate()
+
+ r.checkRightParamsAreUsed()
+ }
+ }
+
+ /**
+ * Runs a test scenario providing a Robot.
+ */
+ fun runTestScenario(consumer: Consumer<ReachabilityGestureListenerFactoryRobotTest>) {
+ val robot = ReachabilityGestureListenerFactoryRobotTest()
+ consumer.accept(robot)
+ }
+
+ class ReachabilityGestureListenerFactoryRobotTest {
+
+ companion object {
+ @JvmStatic
+ private val TASK_ID = 1
+
+ @JvmStatic
+ private val TOKEN = mock<WindowContainerToken>()
+ }
+
+ private val transitions: Transitions
+ private val animationHandler: Transitions.TransitionHandler
+ private val factory: ReachabilityGestureListenerFactory
+ private val wctSupplier: WindowContainerTransactionSupplier
+ private val wct: WindowContainerTransaction
+ private lateinit var obtainedResult: Any
+
+ init {
+ transitions = mock<Transitions>()
+ animationHandler = mock<Transitions.TransitionHandler>()
+ wctSupplier = mock<WindowContainerTransactionSupplier>()
+ wct = mock<WindowContainerTransaction>()
+ doReturn(wct).`when`(wctSupplier).get()
+ factory = ReachabilityGestureListenerFactory(transitions, animationHandler, wctSupplier)
+ }
+
+ fun invokeCreate(taskId: Int = TASK_ID, token: WindowContainerToken? = TOKEN) {
+ obtainedResult = factory.createReachabilityGestureListener(taskId, token)
+ }
+
+ fun checkReachabilityGestureListenerCreated(expected: Boolean = true) {
+ assertEquals(expected, obtainedResult is ReachabilityGestureListener)
+ }
+
+ fun checkRightParamsAreUsed(taskId: Int = TASK_ID, token: WindowContainerToken? = TOKEN) {
+ with(obtainedResult as ReachabilityGestureListener) {
+ // Click outside the bounds
+ updateActivityBounds(Rect(0, 0, 10, 20))
+ onDoubleTap(motionEventAt(50f, 100f))
+ // WindowContainerTransactionSupplier is invoked to create a
+ // WindowContainerTransaction
+ verify(wctSupplier).get()
+ // Verify the right params are passed to startAppCompatReachability()
+ verify(wct).setReachabilityOffset(
+ token!!,
+ taskId,
+ 50,
+ 100
+ )
+ // startTransition() is invoked on Transitions with the right parameters
+ verify(transitions).startTransition(
+ TRANSIT_MOVE_LETTERBOX_REACHABILITY,
+ wct,
+ animationHandler
+ )
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerTest.kt
new file mode 100644
index 000000000000..bc10ea578ffb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/events/ReachabilityGestureListenerTest.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2025 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.wm.shell.compatui.letterbox.events
+
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.window.WindowContainerToken
+import android.window.WindowContainerTransaction
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.WindowContainerTransactionSupplier
+import com.android.wm.shell.compatui.letterbox.LetterboxEvents.motionEventAt
+import com.android.wm.shell.compatui.letterbox.asMode
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TRANSIT_MOVE_LETTERBOX_REACHABILITY
+import java.util.function.Consumer
+import kotlin.test.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+/**
+ * Tests for [ReachabilityGestureListener].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:ReachabilityGestureListenerTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ReachabilityGestureListenerTest : ShellTestCase() {
+
+ @Test
+ fun `Only events outside the bounds are handled`() {
+ runTestScenario { r ->
+ r.updateActivityBounds(Rect(0, 0, 100, 200))
+ r.sendMotionEvent(50, 100)
+
+ r.verifyReachabilityTransitionCreated(expected = false, 50, 100)
+ r.verifyReachabilityTransitionStarted(expected = false)
+ r.verifyEventIsHandled(expected = false)
+
+ r.updateActivityBounds(Rect(0, 0, 10, 50))
+ r.sendMotionEvent(50, 100)
+
+ r.verifyReachabilityTransitionCreated(expected = true, 50, 100)
+ r.verifyReachabilityTransitionStarted(expected = true)
+ r.verifyEventIsHandled(expected = true)
+ }
+ }
+
+ /**
+ * Runs a test scenario providing a Robot.
+ */
+ fun runTestScenario(consumer: Consumer<ReachabilityGestureListenerRobotTest>) {
+ val robot = ReachabilityGestureListenerRobotTest()
+ consumer.accept(robot)
+ }
+
+ class ReachabilityGestureListenerRobotTest(
+ taskId: Int = TASK_ID,
+ token: WindowContainerToken? = TOKEN
+ ) {
+
+ companion object {
+ @JvmStatic
+ private val TASK_ID = 1
+
+ @JvmStatic
+ private val TOKEN = mock<WindowContainerToken>()
+ }
+
+ private val reachabilityListener: ReachabilityGestureListener
+ private val transitions: Transitions
+ private val animationHandler: Transitions.TransitionHandler
+ private val wctSupplier: WindowContainerTransactionSupplier
+ private val wct: WindowContainerTransaction
+ private var eventHandled = false
+
+ init {
+ transitions = mock<Transitions>()
+ animationHandler = mock<Transitions.TransitionHandler>()
+ wctSupplier = mock<WindowContainerTransactionSupplier>()
+ wct = mock<WindowContainerTransaction>()
+ doReturn(wct).`when`(wctSupplier).get()
+ reachabilityListener =
+ ReachabilityGestureListener(
+ taskId,
+ token,
+ transitions,
+ animationHandler,
+ wctSupplier
+ )
+ }
+
+ fun updateActivityBounds(activityBounds: Rect) {
+ reachabilityListener.updateActivityBounds(activityBounds)
+ }
+
+ fun sendMotionEvent(x: Int, y: Int) {
+ eventHandled = reachabilityListener.onDoubleTap(motionEventAt(x.toFloat(), y.toFloat()))
+ }
+
+ fun verifyReachabilityTransitionCreated(
+ expected: Boolean,
+ x: Int,
+ y: Int,
+ taskId: Int = TASK_ID,
+ token: WindowContainerToken? = TOKEN
+ ) {
+ verify(wct, expected.asMode()).setReachabilityOffset(
+ token!!,
+ taskId,
+ x,
+ y
+ )
+ }
+
+ fun verifyReachabilityTransitionStarted(expected: Boolean = true) {
+ verify(transitions, expected.asMode()).startTransition(
+ TRANSIT_MOVE_LETTERBOX_REACHABILITY,
+ wct,
+ animationHandler
+ )
+ }
+
+ fun verifyEventIsHandled(expected: Boolean) {
+ assertEquals(expected, eventHandled)
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
index 0b41952a89d7..e9f92cfd7c56 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
@@ -58,6 +58,7 @@ import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito
@@ -126,17 +127,6 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
}
@Test
- fun startMinimizedModeTransition_callsFreeformTaskTransitionHandler() {
- val wct = WindowContainerTransaction()
- whenever(freeformTaskTransitionHandler.startMinimizedModeTransition(any()))
- .thenReturn(mock())
-
- mixedHandler.startMinimizedModeTransition(wct)
-
- verify(freeformTaskTransitionHandler).startMinimizedModeTransition(wct)
- }
-
- @Test
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX)
fun startRemoveTransition_callsFreeformTaskTransitionHandler() {
val wct = WindowContainerTransaction()
@@ -531,6 +521,131 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX)
+ fun startMinimizedModeTransition_exitByMinimizeTransitionFlagsDisabled_doesNotUseMixedHandler() {
+ val wct = WindowContainerTransaction()
+ val task = createTask(WINDOWING_MODE_FREEFORM)
+ whenever(
+ freeformTaskTransitionHandler.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
+ .thenReturn(mock())
+
+ mixedHandler.startMinimizedModeTransition(
+ wct = wct,
+ taskId = task.taskId,
+ isLastTask = true,
+ )
+
+ verify(freeformTaskTransitionHandler)
+ .startMinimizedModeTransition(eq(wct), eq(task.taskId), eq(true))
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX)
+ fun startMinimizedModeTransition_exitByMinimizeTransitionFlagsEnabled_notLastTask_callsMinimizationHandler() {
+ val wct = WindowContainerTransaction()
+ val minimizingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val minimizingTaskChange = createChange(minimizingTask)
+ val transition = Binder()
+ whenever(
+ transitions.startTransition(eq(Transitions.TRANSIT_MINIMIZE), eq(wct), anyOrNull())
+ )
+ .thenReturn(transition)
+ whenever(
+ desktopMinimizationTransitionHandler.startAnimation(
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ )
+ )
+ .thenReturn(true)
+
+ mixedHandler.startMinimizedModeTransition(
+ wct = wct,
+ taskId = minimizingTask.taskId,
+ isLastTask = false,
+ )
+ val started =
+ mixedHandler.startAnimation(
+ transition = transition,
+ info =
+ createCloseTransitionInfo(
+ Transitions.TRANSIT_MINIMIZE,
+ listOf(minimizingTaskChange),
+ ),
+ startTransaction = mock(),
+ finishTransaction = mock(),
+ finishCallback = {},
+ )
+
+ assertTrue("Should delegate animation to minimization transition handler", started)
+ verify(desktopMinimizationTransitionHandler)
+ .startAnimation(
+ eq(transition),
+ argThat { info -> info.changes.contains(minimizingTaskChange) },
+ any(),
+ any(),
+ any(),
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX)
+ fun startMinimizedModeTransition_exitByMinimizeTransitionFlagsEnabled_withMinimizingLastTask_dispatchesTransition() {
+ val wct = WindowContainerTransaction()
+ val minimizingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val minimizingTaskChange = createChange(minimizingTask)
+ val transition = Binder()
+ whenever(
+ transitions.startTransition(eq(Transitions.TRANSIT_MINIMIZE), eq(wct), anyOrNull())
+ )
+ .thenReturn(transition)
+ whenever(
+ desktopMinimizationTransitionHandler.startAnimation(
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ )
+ )
+ .thenReturn(true)
+
+ mixedHandler.startMinimizedModeTransition(
+ wct = wct,
+ taskId = minimizingTask.taskId,
+ isLastTask = true,
+ )
+ mixedHandler.startAnimation(
+ transition = transition,
+ info =
+ createCloseTransitionInfo(
+ Transitions.TRANSIT_MINIMIZE,
+ listOf(minimizingTaskChange),
+ ),
+ startTransaction = mock(),
+ finishTransaction = mock(),
+ finishCallback = {},
+ )
+
+ verify(transitions)
+ .dispatchTransition(
+ eq(transition),
+ argThat { info -> info.changes.contains(minimizingTaskChange) },
+ any(),
+ any(),
+ any(),
+ eq(mixedHandler),
+ )
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX)
fun addPendingAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() {
val wct = WindowContainerTransaction()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
index 8f45cf4d08fc..20d50aa32f7f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
@@ -23,6 +23,7 @@ import android.graphics.Rect
import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import android.view.Display
import android.view.SurfaceControl
import androidx.test.filters.SmallTest
import com.android.internal.policy.SystemBarUtils
@@ -30,6 +31,7 @@ import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.common.SyncTransactionQueue
@@ -60,18 +62,22 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
private lateinit var taskInfo: RunningTaskInfo
@Mock private lateinit var syncQueue: SyncTransactionQueue
@Mock private lateinit var displayController: DisplayController
+ @Mock private lateinit var display: Display
@Mock private lateinit var taskSurface: SurfaceControl
@Mock private lateinit var taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
@Mock private lateinit var displayLayout: DisplayLayout
@Mock private lateinit var bubbleBoundsProvider: BubbleDropTargetBoundsProvider
private lateinit var visualIndicator: DesktopModeVisualIndicator
+ private val desktopExecutor = TestShellExecutor()
+ private val mainExecutor = TestShellExecutor()
@Before
fun setUp() {
whenever(displayLayout.width()).thenReturn(DISPLAY_BOUNDS.width())
whenever(displayLayout.height()).thenReturn(DISPLAY_BOUNDS.height())
whenever(displayLayout.stableInsets()).thenReturn(STABLE_INSETS)
+ whenever(displayController.getDisplay(anyInt())).thenReturn(display)
whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
whenever(displayController.getDisplay(anyInt())).thenReturn(mContext.display)
whenever(bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(any()))
@@ -305,7 +311,11 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
whenever(bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(/* onLeft= */ true))
.thenReturn(dropTargetBounds)
createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
+ desktopExecutor.flushAll()
+ mainExecutor.flushAll()
visualIndicator.updateIndicatorType(PointF(100f, 1500f))
+ desktopExecutor.flushAll()
+ mainExecutor.flushAll()
animatorTestRule.advanceTimeBy(200)
@@ -322,7 +332,11 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
whenever(bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(/* onLeft= */ false))
.thenReturn(dropTargetBounds)
createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
+ desktopExecutor.flushAll()
+ mainExecutor.flushAll()
visualIndicator.updateIndicatorType(PointF(2300f, 1500f))
+ desktopExecutor.flushAll()
+ mainExecutor.flushAll()
animatorTestRule.advanceTimeBy(200)
@@ -332,6 +346,8 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
private fun createVisualIndicator(dragStartState: DesktopModeVisualIndicator.DragStartState) {
visualIndicator =
DesktopModeVisualIndicator(
+ desktopExecutor,
+ mainExecutor,
syncQueue,
taskInfo,
displayController,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
index 8510441c0557..ed9b97d264f7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
@@ -55,6 +55,8 @@ import org.mockito.Mock
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.spy
import org.mockito.kotlin.any
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.eq
import org.mockito.kotlin.never
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
@@ -894,12 +896,12 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() {
val taskId = 1
val listener = TestListener()
repo.addActiveTaskListener(listener)
- repo.addTask(DEFAULT_DISPLAY, taskId, isVisible = true)
+ repo.addTask(THIRD_DISPLAY, taskId, isVisible = true)
repo.removeTask(THIRD_DISPLAY, taskId)
assertThat(repo.isActiveTask(taskId)).isFalse()
- assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(2)
+ assertThat(listener.activeChangesOnThirdDisplay).isEqualTo(2)
}
@Test
@@ -917,7 +919,7 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() {
fun removeTask_updatesTaskVisibility() {
repo.addDesk(displayId = THIRD_DISPLAY, deskId = THIRD_DISPLAY)
val taskId = 1
- repo.addTask(DEFAULT_DISPLAY, taskId, isVisible = true)
+ repo.addTask(THIRD_DISPLAY, taskId, isVisible = true)
repo.removeTask(THIRD_DISPLAY, taskId)
@@ -1106,6 +1108,30 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun setTaskInFullImmersiveState_inDesk_savedAsInImmersiveState() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+ assertThat(repo.isTaskInFullImmersiveState(6)).isFalse()
+
+ repo.setTaskInFullImmersiveStateInDesk(deskId = 6, taskId = 10, immersive = true)
+
+ assertThat(repo.isTaskInFullImmersiveState(taskId = 10)).isTrue()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeTaskInFullImmersiveState_inDesk_removedAsInImmersiveState() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+ repo.setTaskInFullImmersiveStateInDesk(deskId = 6, taskId = 10, immersive = true)
+
+ repo.setTaskInFullImmersiveStateInDesk(deskId = 6, taskId = 10, immersive = false)
+
+ assertThat(repo.isTaskInFullImmersiveState(taskId = 10)).isFalse()
+ }
+
+ @Test
fun removeTaskInFullImmersiveState_otherWasImmersive_otherRemainsImmersive() {
repo.setTaskInFullImmersiveState(DEFAULT_DISPLAY, taskId = 1, immersive = true)
@@ -1274,14 +1300,146 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() {
assertEquals(SECOND_DISPLAY, repo.getDisplayForDesk(deskId = 8))
}
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun setDeskActive() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+
+ repo.setActiveDesk(DEFAULT_DISPLAY, deskId = 6)
+
+ assertThat(repo.getActiveDeskId(DEFAULT_DISPLAY)).isEqualTo(6)
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun setDeskInactive() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.setActiveDesk(DEFAULT_DISPLAY, deskId = 6)
+
+ repo.setDeskInactive(deskId = 6)
+
+ assertThat(repo.getActiveDeskId(DEFAULT_DISPLAY)).isNull()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun getDeskIdForTask() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+
+ assertThat(repo.getDeskIdForTask(10)).isEqualTo(6)
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeTaskFromDesk_clearsBoundsBeforeMaximize() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+ repo.saveBoundsBeforeMaximize(taskId = 10, bounds = Rect(10, 10, 100, 100))
+
+ repo.removeTaskFromDesk(deskId = 6, taskId = 10)
+
+ assertThat(repo.removeBoundsBeforeMaximize(taskId = 10)).isNull()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeTaskFromDesk_clearsBoundsBeforeImmersive() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+ repo.saveBoundsBeforeFullImmersive(taskId = 10, bounds = Rect(10, 10, 100, 100))
+
+ repo.removeTaskFromDesk(deskId = 6, taskId = 10)
+
+ assertThat(repo.removeBoundsBeforeFullImmersive(taskId = 10)).isNull()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeTaskFromDesk_removesFromZOrderList() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+
+ repo.removeTaskFromDesk(deskId = 6, taskId = 10)
+
+ assertThat(repo.getFreeformTasksIdsInDeskInZOrder(deskId = 6)).doesNotContain(10)
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeTaskFromDesk_removesFromMinimized() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+ repo.minimizeTaskInDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10)
+
+ repo.removeTaskFromDesk(deskId = 6, taskId = 10)
+
+ assertThat(repo.getMinimizedTaskIdsInDesk(deskId = 6)).doesNotContain(10)
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeTaskFromDesk_removesFromImmersive() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+ repo.setTaskInFullImmersiveStateInDesk(deskId = 6, taskId = 10, immersive = true)
+
+ repo.removeTaskFromDesk(deskId = 6, taskId = 10)
+
+ assertThat(repo.isTaskInFullImmersiveState(taskId = 10)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeTaskFromDesk_removesFromActiveTasks() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+
+ repo.removeTaskFromDesk(deskId = 6, taskId = 10)
+
+ assertThat(repo.isActiveTaskInDesk(taskId = 10, deskId = 6)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun removeTaskFromDesk_removesFromVisibleTasks() {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+
+ repo.removeTaskFromDesk(deskId = 6, taskId = 10)
+
+ assertThat(repo.isVisibleTaskInDesk(taskId = 10, deskId = 6)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE)
+ fun removeTaskFromDesk_updatesPersistence() = runTest {
+ repo.addDesk(DEFAULT_DISPLAY, deskId = 6)
+ repo.addTaskToDesk(DEFAULT_DISPLAY, deskId = 6, taskId = 10, isVisible = true)
+ clearInvocations(persistentRepository)
+
+ repo.removeTaskFromDesk(deskId = 6, taskId = 10)
+
+ verify(persistentRepository)
+ .addOrUpdateDesktop(
+ userId = eq(DEFAULT_USER_ID),
+ desktopId = eq(6),
+ visibleTasks = any(),
+ minimizedTasks = any(),
+ freeformTasksInZOrder = any(),
+ )
+ }
+
class TestListener : DesktopRepository.ActiveTasksListener {
var activeChangesOnDefaultDisplay = 0
var activeChangesOnSecondaryDisplay = 0
+ var activeChangesOnThirdDisplay = 0
override fun onActiveTasksChanged(displayId: Int) {
when (displayId) {
DEFAULT_DISPLAY -> activeChangesOnDefaultDisplay++
SECOND_DISPLAY -> activeChangesOnSecondaryDisplay++
+ THIRD_DISPLAY -> activeChangesOnThirdDisplay++
else -> fail("Active task listener received unexpected display id: $displayId")
}
}
@@ -1290,9 +1448,11 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() {
class TestVisibilityListener : DesktopRepository.VisibleTasksListener {
var visibleTasksCountOnDefaultDisplay = 0
var visibleTasksCountOnSecondaryDisplay = 0
+ var visibleTasksCountOnThirdDisplay = 0
var visibleChangesOnDefaultDisplay = 0
var visibleChangesOnSecondaryDisplay = 0
+ var visibleChangesOnThirdDisplay = 0
override fun onTasksVisibilityChanged(displayId: Int, visibleTasksCount: Int) {
when (displayId) {
@@ -1304,6 +1464,10 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() {
visibleTasksCountOnSecondaryDisplay = visibleTasksCount
visibleChangesOnSecondaryDisplay++
}
+ THIRD_DISPLAY -> {
+ visibleTasksCountOnThirdDisplay = visibleTasksCount
+ visibleChangesOnThirdDisplay++
+ }
else -> fail("Visible task listener received unexpected display id: $displayId")
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index be53272185b6..e2c3dda0d927 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -29,6 +29,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.content.ComponentName
+import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.ActivityInfo.CONFIG_DENSITY
@@ -52,6 +53,7 @@ import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.testing.TestableContext
+import android.view.Display
import android.view.Display.DEFAULT_DISPLAY
import android.view.DragEvent
import android.view.Gravity
@@ -149,8 +151,7 @@ import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS
import com.android.wm.shell.transition.Transitions.TransitionHandler
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModelTestsBase.Companion.HOME_LAUNCHER_PACKAGE_NAME
-import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
-import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel
+import com.android.wm.shell.windowdecor.tiling.SnapEventHandler
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.util.Optional
@@ -177,6 +178,7 @@ import org.mockito.ArgumentMatchers.isA
import org.mockito.ArgumentMatchers.isNull
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.mock
@@ -210,6 +212,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Mock lateinit var shellController: ShellController
@Mock lateinit var displayController: DisplayController
@Mock lateinit var displayLayout: DisplayLayout
+ @Mock lateinit var display: Display
@Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer
@Mock lateinit var syncQueue: SyncTransactionQueue
@Mock lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
@@ -230,6 +233,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Mock lateinit var multiInstanceHelper: MultiInstanceHelper
@Mock lateinit var desktopModeVisualIndicator: DesktopModeVisualIndicator
@Mock lateinit var recentTasksController: RecentTasksController
+ @Mock lateinit var snapEventHandler: SnapEventHandler
@Mock private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
@Mock private lateinit var mockSurface: SurfaceControl
@Mock private lateinit var taskbarDesktopTaskListener: TaskbarDesktopTaskListener
@@ -242,9 +246,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
@Mock private lateinit var mockToast: Toast
private lateinit var mockitoSession: StaticMockitoSession
- @Mock private lateinit var desktopTilingDecorViewModel: DesktopTilingDecorViewModel
@Mock private lateinit var bubbleController: BubbleController
- @Mock private lateinit var desktopWindowDecoration: DesktopModeWindowDecoration
@Mock private lateinit var resources: Resources
@Mock
lateinit var desktopModeEnterExitTransitionListener: DesktopModeEntryExitTransitionListener
@@ -258,6 +260,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Mock private lateinit var userProfileContexts: UserProfileContexts
@Mock private lateinit var desksTransitionsObserver: DesksTransitionObserver
@Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var mockDisplayContext: Context
private lateinit var controller: DesktopTasksController
private lateinit var shellInit: ShellInit
@@ -270,6 +273,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
private lateinit var spyContext: TestableContext
private val shellExecutor = TestShellExecutor()
+ private val bgExecutor = TestShellExecutor()
// Mock running tasks are registered here so we can get the list from mock shell task organizer
private val runningTasks = mutableListOf<RunningTaskInfo>()
@@ -323,9 +327,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
desktopModeCompatPolicy = spy(DesktopModeCompatPolicy(spyContext))
whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
- whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() }
+ whenever(transitions.startTransition(anyInt(), any(), anyOrNull())).thenAnswer { Binder() }
whenever(enterDesktopTransitionHandler.moveToDesktop(any(), any())).thenAnswer { Binder() }
+ whenever(exitDesktopTransitionHandler.startTransition(any(), any(), any(), any()))
+ .thenReturn(Binder())
whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
+ whenever(displayController.getDisplayContext(anyInt())).thenReturn(mockDisplayContext)
+ whenever(displayController.getDisplay(anyInt())).thenReturn(display)
whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(STABLE_BOUNDS)
}
@@ -372,6 +380,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
recentsTransitionStateListener = captor.firstValue
controller.taskbarDesktopTaskListener = taskbarDesktopTaskListener
+ controller.setSnapEventHandler(snapEventHandler)
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -408,13 +417,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
recentsTransitionHandler,
multiInstanceHelper,
shellExecutor,
+ bgExecutor,
Optional.of(desktopTasksLimiter),
recentTasksController,
mockInteractionJankMonitor,
mockHandler,
desktopModeEventLogger,
desktopModeUiEventLogger,
- desktopTilingDecorViewModel,
desktopWallpaperActivityTokenProvider,
Optional.of(bubbleController),
overviewToDesktopTransitionObserver,
@@ -910,7 +919,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperDisabled() {
taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY)
val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY)
@@ -2032,6 +2044,30 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun moveToFullscreen_fromDesk_reparentsToTaskDisplayArea() {
+ val task = setUpFreeformTask()
+ val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
+
+ controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ wct.assertHop(ReparentPredicate(token = task.token, parentToken = tda.token, toTop = true))
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun moveToFullscreen_fromDesk_deactivatesDesk() {
+ val task = setUpFreeformTask()
+ val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
+
+ controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ verify(desksOrganizer).deactivateDesk(wct, deskId = 0)
+ }
+
+ @Test
fun moveToFullscreen_tdaFullscreen_windowingModeSetToUndefined() {
val task = setUpFreeformTask()
val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
@@ -2046,6 +2082,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER)
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun moveToFullscreen_tdaFullscreen_windowingModeUndefined_removesWallpaperActivity() {
whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
val homeTask = setUpHomeTask()
@@ -2071,6 +2108,60 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
+ fun moveToFullscreen_tdaFullscreen_windowingModeUndefined_removesWallpaperActivity_multiDesksEnabled() {
+ whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
+ setUpHomeTask()
+ val task = setUpFreeformTask()
+ assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+ .configuration
+ .windowConfiguration
+ .windowingMode = WINDOWING_MODE_FULLSCREEN
+
+ controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
+ verify(desktopModeEnterExitTransitionListener)
+ .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
+ assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
+ // Removes wallpaper activity when leaving desktop
+ wct.assertReorder(wallpaperToken, toTop = false)
+ }
+
+ @Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
+ fun moveToFullscreen_tdaFullscreen_windowingModeUndefined_homeBehindFullscreen_multiDesksEnabled() {
+ whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
+ val homeTask = setUpHomeTask()
+ val task = setUpFreeformTask()
+ assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+ .configuration
+ .windowConfiguration
+ .windowingMode = WINDOWING_MODE_FULLSCREEN
+
+ controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
+ verify(desktopModeEnterExitTransitionListener)
+ .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
+ assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
+ // Moves home task behind the fullscreen task
+ val homeReorderIndex = wct.indexOfReorder(homeTask, toTop = true)
+ val fullscreenReorderIndex = wct.indexOfReorder(task, toTop = true)
+ assertThat(homeReorderIndex).isNotEqualTo(-1)
+ assertThat(fullscreenReorderIndex).isNotEqualTo(-1)
+ assertThat(fullscreenReorderIndex).isGreaterThan(homeReorderIndex)
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER)
fun moveToFullscreen_tdaFreeform_enforcedDesktop_doesNotReorderHome() {
whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
@@ -2086,9 +2177,9 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val wct = getLatestExitDesktopWct()
verify(desktopModeEnterExitTransitionListener)
.onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
- assertThat(wct.hierarchyOps).hasSize(1)
// Removes wallpaper activity when leaving desktop but doesn't reorder home or the task
- wct.assertReorderAt(index = 0, wallpaperToken, toTop = false)
+ wct.assertReorder(wallpaperToken, toTop = false)
+ wct.assertWithoutHop(ReorderPredicate(homeTask.token, toTop = null))
}
@Test
@@ -2106,6 +2197,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER)
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun moveToFullscreen_tdaFreeform_windowingModeFullscreen_removesWallpaperActivity() {
val homeTask = setUpHomeTask()
val task = setUpFreeformTask()
@@ -2131,6 +2223,61 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
+ fun moveToFullscreen_tdaFreeform_windowingModeFullscreen_removesWallpaperActivity_multiDesksEnabled() {
+ val homeTask = setUpHomeTask()
+ val task = setUpFreeformTask()
+
+ assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+ .configuration
+ .windowConfiguration
+ .windowingMode = WINDOWING_MODE_FREEFORM
+
+ controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
+ assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN)
+ verify(desktopModeEnterExitTransitionListener)
+ .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
+ // Removes wallpaper activity when leaving desktop
+ wct.assertReorder(wallpaperToken, toTop = false)
+ }
+
+ @Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
+ fun moveToFullscreen_tdaFreeform_windowingModeFullscreen_homeBehindFullscreen_multiDesksEnabled() {
+ val homeTask = setUpHomeTask()
+ val task = setUpFreeformTask()
+
+ assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+ .configuration
+ .windowConfiguration
+ .windowingMode = WINDOWING_MODE_FREEFORM
+
+ controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
+ assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN)
+ verify(desktopModeEnterExitTransitionListener)
+ .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
+ // Moves home task behind the fullscreen task
+ val homeReorderIndex = wct.indexOfReorder(homeTask, toTop = true)
+ val fullscreenReorderIndex = wct.indexOfReorder(task, toTop = true)
+ assertThat(homeReorderIndex).isNotEqualTo(-1)
+ assertThat(fullscreenReorderIndex).isNotEqualTo(-1)
+ assertThat(fullscreenReorderIndex).isGreaterThan(homeReorderIndex)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun moveToFullscreen_multipleVisibleNonMinimizedTasks_doesNotRemoveWallpaperActivity() {
val homeTask = setUpHomeTask()
val task1 = setUpFreeformTask()
@@ -2157,6 +2304,29 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun moveToFullscreen_multipleVisibleNonMinimizedTasks_doesNotRemoveWallpaperActivity_multiDesksEnabled() {
+ val homeTask = setUpHomeTask()
+ val task1 = setUpFreeformTask()
+ // Setup task2
+ setUpFreeformTask()
+
+ val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)
+ assertNotNull(tdaInfo).configuration.windowConfiguration.windowingMode =
+ WINDOWING_MODE_FULLSCREEN
+
+ controller.moveToFullscreen(task1.taskId, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val task1Change = assertNotNull(wct.changes[task1.token.asBinder()])
+ assertThat(task1Change.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
+ verify(desktopModeEnterExitTransitionListener)
+ .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
+ // Does not remove wallpaper activity, as desktop still has a visible desktop task
+ wct.assertWithoutHop(ReorderPredicate(wallpaperToken, toTop = false))
+ }
+
+ @Test
fun moveToFullscreen_nonExistentTask_doesNothing() {
controller.moveToFullscreen(999, transitionSource = UNKNOWN)
verifyExitDesktopWCTNotExecuted()
@@ -2752,22 +2922,97 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onDesktopWindowClose_lastWindow_deactivatesDesk() {
+ val task = setUpFreeformTask()
+ val wct = WindowContainerTransaction()
+
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, task)
+
+ verify(desksOrganizer).deactivateDesk(wct, deskId = 0)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onDesktopWindowClose_lastWindow_addsPendingDeactivateTransition() {
+ val task = setUpFreeformTask()
+ val wct = WindowContainerTransaction()
+
+ val transition = Binder()
+ val runOnTransitStart =
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, task)
+ runOnTransitStart(transition)
+
+ verify(desksTransitionsObserver)
+ .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId = 0))
+ }
+
+ @Test
fun onDesktopWindowMinimize_noActiveTask_doesntRemoveWallpaper() {
val task = setUpFreeformTask(active = false)
val transition = Binder()
- whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
.thenReturn(transition)
controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
val captor = argumentCaptor<WindowContainerTransaction>()
- verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+ verify(freeformTaskTransitionStarter)
+ .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(false))
captor.firstValue.hierarchyOps.none { hop ->
hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder()
}
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onDesktopWindowMinimize_lastWindow_deactivatesDesk() {
+ val task = setUpFreeformTask()
+ val transition = Binder()
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
+ .thenReturn(transition)
+
+ controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
+
+ val captor = argumentCaptor<WindowContainerTransaction>()
+ verify(freeformTaskTransitionStarter)
+ .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(true))
+ verify(desksOrganizer).deactivateDesk(captor.firstValue, deskId = 0)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onDesktopWindowMinimize_lastWindow_addsPendingDeactivateTransition() {
+ val task = setUpFreeformTask()
+ val transition = Binder()
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
+ .thenReturn(transition)
+
+ controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
+
+ verify(desksTransitionsObserver)
+ .addPendingTransition(DeskTransition.DeactivateDesk(token = transition, deskId = 0))
+ }
+
+ @Test
fun onPipTaskMinimize_autoEnterEnabled_startPipTransition() {
val task = setUpPipTask(autoEnterEnabled = true)
val handler = mock(TransitionHandler::class.java)
@@ -2777,18 +3022,26 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
verify(freeformTaskTransitionStarter).startPipTransition(any())
- verify(freeformTaskTransitionStarter, never()).startMinimizedModeTransition(any())
+ verify(freeformTaskTransitionStarter, never())
+ .startMinimizedModeTransition(any(), anyInt(), anyBoolean())
}
@Test
fun onPipTaskMinimize_autoEnterDisabled_startMinimizeTransition() {
val task = setUpPipTask(autoEnterEnabled = false)
- whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
.thenReturn(Binder())
controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
- verify(freeformTaskTransitionStarter).startMinimizedModeTransition(any())
+ verify(freeformTaskTransitionStarter)
+ .startMinimizedModeTransition(any(), eq(task.taskId), anyBoolean())
verify(freeformTaskTransitionStarter, never()).startPipTransition(any())
}
@@ -2812,13 +3065,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
fun onDesktopWindowMinimize_singleActiveTask_noWallpaperActivityToken_doesntRemoveWallpaper() {
val task = setUpFreeformTask(active = true)
val transition = Binder()
- whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
.thenReturn(transition)
controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
val captor = argumentCaptor<WindowContainerTransaction>()
- verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+ verify(freeformTaskTransitionStarter)
+ .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(true))
captor.firstValue.hierarchyOps.none { hop -> hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK }
}
@@ -2827,14 +3087,21 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
fun onTaskMinimize_singleActiveTask_hasWallpaperActivityToken_removesWallpaper() {
val task = setUpFreeformTask()
val transition = Binder()
- whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
.thenReturn(transition)
// The only active task is being minimized.
controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
val captor = argumentCaptor<WindowContainerTransaction>()
- verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+ verify(freeformTaskTransitionStarter)
+ .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(true))
// Adds remove wallpaper operation
captor.firstValue.assertReorderAt(index = 0, wallpaperToken, toTop = false)
}
@@ -2843,7 +3110,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
fun onDesktopWindowMinimize_singleActiveTask_alreadyMinimized_doesntRemoveWallpaper() {
val task = setUpFreeformTask()
val transition = Binder()
- whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
.thenReturn(transition)
taskRepository.minimizeTask(DEFAULT_DISPLAY, task.taskId)
@@ -2851,7 +3124,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
val captor = argumentCaptor<WindowContainerTransaction>()
- verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+ verify(freeformTaskTransitionStarter)
+ .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(false))
captor.firstValue.hierarchyOps.none { hop ->
hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder()
}
@@ -2862,13 +3136,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task1 = setUpFreeformTask(active = true)
setUpFreeformTask(active = true)
val transition = Binder()
- whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
.thenReturn(transition)
controller.minimizeTask(task1, MinimizeReason.MINIMIZE_BUTTON)
val captor = argumentCaptor<WindowContainerTransaction>()
- verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+ verify(freeformTaskTransitionStarter)
+ .startMinimizedModeTransition(captor.capture(), eq(task1.taskId), eq(false))
captor.firstValue.hierarchyOps.none { hop ->
hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder()
}
@@ -2880,7 +3161,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task1 = setUpFreeformTask(active = true)
val task2 = setUpFreeformTask(active = true)
val transition = Binder()
- whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
.thenReturn(transition)
taskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId)
@@ -2888,7 +3175,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
controller.minimizeTask(task1, MinimizeReason.MINIMIZE_BUTTON)
// Adds remove wallpaper operation
val captor = argumentCaptor<WindowContainerTransaction>()
- verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture())
+ verify(freeformTaskTransitionStarter)
+ .startMinimizedModeTransition(captor.capture(), eq(task1.taskId), eq(true))
// Adds remove wallpaper operation
captor.firstValue.assertReorderAt(index = 0, wallpaperToken, toTop = false)
}
@@ -2897,7 +3185,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
fun onDesktopWindowMinimize_triesToExitImmersive() {
val task = setUpFreeformTask()
val transition = Binder()
- whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
.thenReturn(transition)
controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
@@ -2910,7 +3204,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val task = setUpFreeformTask()
val transition = Binder()
val runOnTransit = RunOnStartTransitionCallback()
- whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
.thenReturn(transition)
whenever(mMockDesktopImmersiveController.exitImmersiveIfApplicable(any(), eq(task), any()))
.thenReturn(
@@ -3964,10 +4264,11 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val taskChange = assertNotNull(wct.changes[task2.token.asBinder()])
assertThat(taskChange.windowingMode)
.isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
- wct.assertReorderAt(index = 0, wallpaperToken, toTop = false)
+ wct.assertReorder(wallpaperToken, toTop = false)
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun moveFocusedTaskToFullscreen_multipleVisibleTasks_doesNotRemoveWallpaperActivity() {
val homeTask = setUpHomeTask()
val task1 = setUpFreeformTask()
@@ -3991,6 +4292,52 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun moveFocusedTaskToFullscreen_multipleVisibleTasks_doesNotRemoveWallpaperActivity_multiDesksEnabled() {
+ val homeTask = setUpHomeTask()
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val task3 = setUpFreeformTask()
+
+ task1.isFocused = false
+ task2.isFocused = true
+ task3.isFocused = false
+ controller.enterFullscreen(DEFAULT_DISPLAY, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task2.token.asBinder()])
+ assertThat(taskChange.windowingMode)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+ // Does not remove wallpaper activity
+ wct.assertWithoutHop(ReorderPredicate(wallpaperToken, toTop = null))
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun moveFocusedTaskToFullscreen_multipleVisibleTasks_fullscreenOverHome_multiDesksEnabled() {
+ val homeTask = setUpHomeTask()
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val task3 = setUpFreeformTask()
+
+ task1.isFocused = false
+ task2.isFocused = true
+ task3.isFocused = false
+ controller.enterFullscreen(DEFAULT_DISPLAY, transitionSource = UNKNOWN)
+
+ val wct = getLatestExitDesktopWct()
+ val taskChange = assertNotNull(wct.changes[task2.token.asBinder()])
+ assertThat(taskChange.windowingMode)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+ // Moves home task behind the fullscreen task
+ val homeReorderIndex = wct.indexOfReorder(homeTask, toTop = true)
+ val fullscreenReorderIndex = wct.indexOfReorder(task2, toTop = true)
+ assertThat(homeReorderIndex).isNotEqualTo(-1)
+ assertThat(fullscreenReorderIndex).isNotEqualTo(-1)
+ assertThat(fullscreenReorderIndex).isGreaterThan(homeReorderIndex)
+ }
+
+ @Test
@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
fun moveFocusedTaskToFullscreen_minimizedPipPresent_removeWallpaperActivity() {
val freeformTask = setUpFreeformTask()
@@ -4412,7 +4759,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
validDragArea = Rect(0, 50, 2000, 2000),
dragStartBounds = Rect(),
motionEvent,
- desktopWindowDecoration,
)
val rectAfterEnd = Rect(100, 50, 500, 1150)
verify(transitions)
@@ -4450,7 +4796,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
validDragArea = Rect(0, 50, 2000, 2000),
dragStartBounds = Rect(),
motionEvent,
- desktopWindowDecoration,
)
verify(transitions)
@@ -4490,7 +4835,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
validDragArea = Rect(0, 50, 2000, 2000),
dragStartBounds = Rect(),
motionEvent,
- desktopWindowDecoration,
)
verify(transitions)
@@ -4531,7 +4875,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
validDragArea = Rect(0, 50, 2000, 2000),
dragStartBounds = Rect(),
motionEvent,
- desktopWindowDecoration,
)
// Assert the task exits desktop mode
@@ -4569,7 +4912,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
validDragArea = Rect(0, 50, 2000, 2000),
dragStartBounds = Rect(),
motionEvent,
- desktopWindowDecoration,
)
// Assert bounds set to stable bounds
@@ -4625,7 +4967,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
validDragArea = Rect(0, 50, 2000, 2000),
dragStartBounds = Rect(),
motionEvent,
- desktopWindowDecoration,
)
// Assert that task is NOT updated via WCT
@@ -4857,7 +5198,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val optionsCaptor = argumentCaptor<Bundle>()
runOpenInstance(task, taskToRequest.taskId)
verify(splitScreenController)
- .startTask(anyInt(), anyInt(), optionsCaptor.capture(), anyOrNull())
+ .startTask(anyInt(), anyInt(), optionsCaptor.capture(), anyOrNull(), any())
assertThat(ActivityOptions.fromBundle(optionsCaptor.firstValue).launchWindowingMode)
.isEqualTo(WINDOWING_MODE_MULTI_WINDOW)
}
@@ -4871,7 +5212,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val optionsCaptor = argumentCaptor<Bundle>()
runOpenInstance(task, taskToRequest.taskId)
verify(splitScreenController)
- .startTask(anyInt(), anyInt(), optionsCaptor.capture(), anyOrNull())
+ .startTask(anyInt(), anyInt(), optionsCaptor.capture(), anyOrNull(), any())
assertThat(ActivityOptions.fromBundle(optionsCaptor.firstValue).launchWindowingMode)
.isEqualTo(WINDOWING_MODE_MULTI_WINDOW)
}
@@ -5045,7 +5386,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
SnapPosition.LEFT,
ResizeTrigger.SNAP_LEFT_MENU,
InputMethod.TOUCH,
- desktopWindowDecoration,
)
// Assert bounds set to stable bounds
val wct = getLatestToggleResizeDesktopTaskWct(currentDragBounds)
@@ -5091,7 +5431,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
SnapPosition.LEFT,
ResizeTrigger.SNAP_LEFT_MENU,
InputMethod.TOUCH,
- desktopWindowDecoration,
)
// Assert that task is NOT updated via WCT
verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any())
@@ -5135,7 +5474,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
currentDragBounds,
preDragBounds,
motionEvent,
- desktopWindowDecoration,
)
val wct = getLatestToggleResizeDesktopTaskWct(currentDragBounds)
assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
@@ -5165,7 +5503,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
currentDragBounds,
preDragBounds,
motionEvent,
- desktopWindowDecoration,
)
verify(mReturnToDragStartAnimator)
.start(
@@ -5190,7 +5527,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
SnapPosition.LEFT,
ResizeTrigger.SNAP_LEFT_MENU,
InputMethod.MOUSE,
- desktopWindowDecoration,
)
// Assert that task is NOT updated via WCT
@@ -5217,7 +5553,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
SnapPosition.LEFT,
ResizeTrigger.SNAP_LEFT_MENU,
InputMethod.MOUSE,
- desktopWindowDecoration,
)
// Assert bounds set to half of the stable bounds
@@ -6270,15 +6605,46 @@ private fun WindowContainerTransaction.assertWithoutHop(
assertThat(hierarchyOps.none(predicate)).isTrue()
}
-private fun WindowContainerTransaction.assertReorder(
+private fun WindowContainerTransaction.indexOfReorder(
task: RunningTaskInfo,
toTop: Boolean? = null,
-) {
- assertHop { hop ->
+): Int {
+ val hop = hierarchyOps.singleOrNull(ReorderPredicate(task.token, toTop)) ?: return -1
+ return hierarchyOps.indexOf(hop)
+}
+
+private class ReorderPredicate(val token: WindowContainerToken, val toTop: Boolean? = null) :
+ ((WindowContainerTransaction.HierarchyOp) -> Boolean) {
+ override fun invoke(hop: WindowContainerTransaction.HierarchyOp): Boolean =
hop.type == HIERARCHY_OP_TYPE_REORDER &&
(toTop == null || hop.toTop == toTop) &&
- hop.container == task.token.asBinder()
- }
+ hop.container == token.asBinder()
+}
+
+private class ReparentPredicate(
+ val token: WindowContainerToken,
+ val parentToken: WindowContainerToken,
+ val toTop: Boolean? = null,
+) : ((WindowContainerTransaction.HierarchyOp) -> Boolean) {
+ override fun invoke(hop: WindowContainerTransaction.HierarchyOp): Boolean =
+ hop.isReparent &&
+ (toTop == null || hop.toTop == toTop) &&
+ hop.container == token.asBinder() &&
+ hop.newParent == parentToken.asBinder()
+}
+
+private fun WindowContainerTransaction.assertReorder(
+ task: RunningTaskInfo,
+ toTop: Boolean? = null,
+) {
+ assertReorder(task.token, toTop)
+}
+
+private fun WindowContainerTransaction.assertReorder(
+ token: WindowContainerToken,
+ toTop: Boolean? = null,
+) {
+ assertHop(ReorderPredicate(token, toTop))
}
private fun WindowContainerTransaction.assertReorderAt(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index 1732875f1d57..85f6cd36992d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -25,6 +25,8 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestRunningTaskInfoBuilder
+import com.android.wm.shell.bubbles.BubbleController
+import com.android.wm.shell.bubbles.BubbleTransitions
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP
@@ -34,6 +36,7 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
+import java.util.Optional
import java.util.function.Supplier
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
@@ -48,6 +51,7 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.MockitoSession
+import org.mockito.kotlin.argThat
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.times
@@ -71,6 +75,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() {
@Mock private lateinit var draggedTaskLeash: SurfaceControl
@Mock private lateinit var homeTaskLeash: SurfaceControl
@Mock private lateinit var desktopUserRepositories: DesktopUserRepositories
+ @Mock private lateinit var bubbleController: BubbleController
private val transactionSupplier = Supplier { mock<SurfaceControl.Transaction>() }
@@ -87,6 +92,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() {
taskDisplayAreaOrganizer,
desktopUserRepositories,
mockInteractionJankMonitor,
+ Optional.of(bubbleController),
transactionSupplier,
)
.apply { setSplitScreenController(splitScreenController) }
@@ -97,6 +103,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() {
taskDisplayAreaOrganizer,
desktopUserRepositories,
mockInteractionJankMonitor,
+ Optional.of(bubbleController),
transactionSupplier,
)
.apply { setSplitScreenController(splitScreenController) }
@@ -169,6 +176,32 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() {
}
@Test
+ fun startDragToDesktop_cancelledBeforeReady_verifyBubbleLeftCancel() {
+ performEarlyCancel(
+ defaultHandler,
+ DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_LEFT,
+ )
+ verify(bubbleController)
+ .expandStackAndSelectBubble(
+ any<RunningTaskInfo>(),
+ argThat<BubbleTransitions.DragData> { isReleasedOnLeft },
+ )
+ }
+
+ @Test
+ fun startDragToDesktop_cancelledBeforeReady_verifyBubbleRightCancel() {
+ performEarlyCancel(
+ defaultHandler,
+ DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_RIGHT,
+ )
+ verify(bubbleController)
+ .expandStackAndSelectBubble(
+ any<RunningTaskInfo>(),
+ argThat<BubbleTransitions.DragData> { !isReleasedOnLeft },
+ )
+ }
+
+ @Test
fun startDragToDesktop_aborted_finishDropped() {
val task = createTask()
// Simulate transition is started.
@@ -343,6 +376,40 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() {
}
@Test
+ fun cancelDragToDesktop_bubbleLeftCancelType_bubbleRequested() {
+ startDrag(defaultHandler)
+
+ // Then user cancelled it, requesting bubble.
+ defaultHandler.cancelDragToDesktopTransition(
+ DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_LEFT
+ )
+
+ // Verify the request went through bubble controller.
+ verify(bubbleController)
+ .expandStackAndSelectBubble(
+ any<RunningTaskInfo>(),
+ argThat<BubbleTransitions.DragData> { isReleasedOnLeft },
+ )
+ }
+
+ @Test
+ fun cancelDragToDesktop_bubbleRightCancelType_bubbleRequested() {
+ startDrag(defaultHandler)
+
+ // Then user cancelled it, requesting bubble.
+ defaultHandler.cancelDragToDesktopTransition(
+ DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_RIGHT
+ )
+
+ // Verify the request went through bubble controller.
+ verify(bubbleController)
+ .expandStackAndSelectBubble(
+ any<RunningTaskInfo>(),
+ argThat<BubbleTransitions.DragData> { !isReleasedOnLeft },
+ )
+ }
+
+ @Test
fun cancelDragToDesktop_startWasNotReady_animateCancel() {
val task = createTask()
// Simulate transition is started and is ready to animate.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt
new file mode 100644
index 000000000000..79b0f1c7eadd
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.desktopmode
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
+import android.platform.test.annotations.EnableFlags
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.Display
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.TestRunningTaskInfoBuilder
+import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider
+import com.android.wm.shell.windowdecor.WindowDecoration.SurfaceControlViewHostFactory
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyZeroInteractions
+import org.mockito.kotlin.whenever
+
+/**
+ * Test class for [VisualIndicatorViewContainer] and [VisualIndicatorAnimator]
+ *
+ * Usage: atest WMShellUnitTests:VisualIndicatorViewContainerTest
+ */
+@SmallTest
+@RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+class VisualIndicatorViewContainerTest : ShellTestCase() {
+ @Mock private lateinit var view: View
+ @Mock private lateinit var displayLayout: DisplayLayout
+ @Mock private lateinit var displayController: DisplayController
+ @Mock private lateinit var taskSurface: SurfaceControl
+ @Mock private lateinit var syncQueue: SyncTransactionQueue
+ @Mock private lateinit var mockSurfaceControlViewHostFactory: SurfaceControlViewHostFactory
+ @Mock private lateinit var mockBackground: LayerDrawable
+ @Mock private lateinit var bubbleDropTargetBoundsProvider: BubbleDropTargetBoundsProvider
+ private val taskInfo: RunningTaskInfo = createTaskInfo()
+ private val mainExecutor = TestShellExecutor()
+ private val desktopExecutor = TestShellExecutor()
+
+ @Before
+ fun setUp() {
+ whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
+ whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(DISPLAY_BOUNDS)
+ }
+ whenever(mockSurfaceControlViewHostFactory.create(any(), any(), any()))
+ .thenReturn(mock(SurfaceControlViewHost::class.java))
+ }
+
+ @Test
+ fun testTransitionIndicator_sameTypeReturnsEarly() {
+ val spyViewContainer = setupSpyViewContainer()
+ // Test early return on startType == endType.
+ spyViewContainer.transitionIndicator(
+ taskInfo,
+ displayController,
+ DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ )
+ desktopExecutor.flushAll()
+ verify(spyViewContainer)
+ .transitionIndicator(
+ eq(taskInfo),
+ eq(displayController),
+ eq(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR),
+ eq(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR),
+ )
+ // Assert fadeIn, fadeOut, and animateIndicatorType were not called.
+ verifyZeroInteractions(spyViewContainer)
+ }
+
+ @Test
+ fun testTransitionIndicator_firstTypeNoIndicator_callsFadeIn() {
+ val spyViewContainer = setupSpyViewContainer()
+ spyViewContainer.transitionIndicator(
+ taskInfo,
+ displayController,
+ DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR,
+ DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ )
+ desktopExecutor.flushAll()
+ verify(spyViewContainer).fadeInIndicator(any(), any())
+ }
+
+ @Test
+ fun testTransitionIndicator_secondTypeNoIndicator_callsFadeOut() {
+ val spyViewContainer = setupSpyViewContainer()
+ spyViewContainer.transitionIndicator(
+ taskInfo,
+ displayController,
+ DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR,
+ )
+ desktopExecutor.flushAll()
+ verify(spyViewContainer)
+ .fadeOutIndicator(
+ any(),
+ eq(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR),
+ anyOrNull(),
+ )
+ }
+
+ @Test
+ fun testTransitionIndicator_differentTypes_callsTransitionIndicator() {
+ val spyViewContainer = setupSpyViewContainer()
+ spyViewContainer.transitionIndicator(
+ taskInfo,
+ displayController,
+ DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR,
+ )
+ desktopExecutor.flushAll()
+ verify(spyViewContainer)
+ .transitionIndicator(
+ any(),
+ any(),
+ eq(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR),
+ eq(DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR),
+ )
+ }
+
+ @Test
+ fun testFadeInBoundsCalculation() {
+ val spyIndicator = setupSpyViewContainer()
+ val animator =
+ spyIndicator.indicatorView?.let {
+ VisualIndicatorViewContainer.VisualIndicatorAnimator.fadeBoundsIn(
+ it,
+ DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ displayLayout,
+ bubbleDropTargetBoundsProvider,
+ )
+ }
+ assertThat(animator?.indicatorStartBounds).isEqualTo(Rect(15, 15, 985, 985))
+ assertThat(animator?.indicatorEndBounds).isEqualTo(Rect(0, 0, 1000, 1000))
+ }
+
+ @Test
+ fun testFadeOutBoundsCalculation() {
+ val spyIndicator = setupSpyViewContainer()
+ val animator =
+ spyIndicator.indicatorView?.let {
+ VisualIndicatorViewContainer.VisualIndicatorAnimator.fadeBoundsOut(
+ it,
+ DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ displayLayout,
+ bubbleDropTargetBoundsProvider,
+ )
+ }
+ assertThat(animator?.indicatorStartBounds).isEqualTo(Rect(0, 0, 1000, 1000))
+ assertThat(animator?.indicatorEndBounds).isEqualTo(Rect(15, 15, 985, 985))
+ }
+
+ @Test
+ fun testChangeIndicatorTypeBoundsCalculation() {
+ // Test fullscreen to split-left bounds.
+ var animator =
+ VisualIndicatorViewContainer.VisualIndicatorAnimator.animateIndicatorType(
+ view,
+ displayLayout,
+ DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR,
+ bubbleDropTargetBoundsProvider,
+ )
+ // Test desktop to split-right bounds.
+ animator =
+ VisualIndicatorViewContainer.VisualIndicatorAnimator.animateIndicatorType(
+ view,
+ displayLayout,
+ DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR,
+ DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR,
+ bubbleDropTargetBoundsProvider,
+ )
+ }
+
+ private fun setupSpyViewContainer(): VisualIndicatorViewContainer {
+ val viewContainer =
+ VisualIndicatorViewContainer(
+ desktopExecutor,
+ mainExecutor,
+ SurfaceControl.Builder(),
+ syncQueue,
+ mockSurfaceControlViewHostFactory,
+ bubbleDropTargetBoundsProvider,
+ )
+ viewContainer.createView(
+ context,
+ mock(Display::class.java),
+ displayLayout,
+ taskInfo,
+ taskSurface,
+ )
+ desktopExecutor.flushAll()
+ viewContainer.indicatorView?.background = mockBackground
+ whenever(mockBackground.findDrawableByLayerId(anyInt()))
+ .thenReturn(mock(Drawable::class.java))
+ return spy(viewContainer)
+ }
+
+ private fun createTaskInfo(): RunningTaskInfo {
+ val taskDescriptionBuilder = ActivityManager.TaskDescription.Builder()
+ return TestRunningTaskInfoBuilder()
+ .setDisplayId(Display.DEFAULT_DISPLAY)
+ .setTaskDescriptionBuilder(taskDescriptionBuilder)
+ .setVisible(true)
+ .build()
+ }
+
+ companion object {
+ private val DISPLAY_BOUNDS = Rect(0, 0, 1000, 1000)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProviderTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProviderTest.kt
new file mode 100644
index 000000000000..aa4e9aaf248e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProviderTest.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.desktopmode.desktopwallpaperactivity
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.Display.DEFAULT_DISPLAY
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.MockToken
+import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Test class for [DesktopWallpaperActivityTokenProvider]
+ *
+ * Usage: atest WMShellUnitTests:DesktopWallpaperActivityTokenProviderTest
+ */
+@SmallTest
+@RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class DesktopWallpaperActivityTokenProviderTest : ShellTestCase() {
+
+ private lateinit var provider: DesktopWallpaperActivityTokenProvider
+ private val DEFAULT_DISPLAY = 0
+ private val SECONDARY_DISPLAY = 1
+
+ @Before
+ fun setUp() {
+ provider = DesktopWallpaperActivityTokenProvider()
+ }
+
+ @Test
+ fun setToken_setsTokenForDisplay() {
+ val token = MockToken().token()
+
+ provider.setToken(token, DEFAULT_DISPLAY)
+
+ assertThat(provider.getToken(DEFAULT_DISPLAY)).isEqualTo(token)
+ }
+
+ @Test
+ fun setToken_overwritesExistingTokenForDisplay() {
+ val token1 = MockToken().token()
+ val token2 = MockToken().token()
+
+ provider.setToken(token1, DEFAULT_DISPLAY)
+ provider.setToken(token2, DEFAULT_DISPLAY)
+
+ assertThat(provider.getToken(DEFAULT_DISPLAY)).isEqualTo(token2)
+ }
+
+ @Test
+ fun getToken_returnsNullForNonExistentDisplay() {
+ assertThat(provider.getToken(SECONDARY_DISPLAY)).isNull()
+ }
+
+ @Test
+ fun removeToken_removesTokenForDisplay() {
+ val token = MockToken().token()
+
+ provider.setToken(token, DEFAULT_DISPLAY)
+ provider.removeToken(DEFAULT_DISPLAY)
+
+ assertThat(provider.getToken(DEFAULT_DISPLAY)).isNull()
+ }
+
+ @Test
+ fun removeToken_withToken_removesTokenForDisplay() {
+ val token = MockToken().token()
+
+ provider.setToken(token, DEFAULT_DISPLAY)
+ provider.removeToken(token)
+
+ assertThat(provider.getToken(DEFAULT_DISPLAY)).isNull()
+ }
+
+ @Test
+ fun removeToken_doesNothingForNonExistentDisplay() {
+ provider.removeToken(SECONDARY_DISPLAY)
+
+ assertThat(provider.getToken(SECONDARY_DISPLAY)).isNull()
+ }
+
+ @Test
+ fun removeToken_withNonExistentToken_doesNothing() {
+ val token1 = MockToken().token()
+ val token2 = MockToken().token()
+
+ provider.setToken(token1, DEFAULT_DISPLAY)
+ provider.removeToken(token2)
+
+ assertThat(provider.getToken(DEFAULT_DISPLAY)).isEqualTo(token1)
+ }
+
+ @Test
+ fun multipleDisplays_tokensAreIndependent() {
+ val token1 = MockToken().token()
+ val token2 = MockToken().token()
+
+ provider.setToken(token1, DEFAULT_DISPLAY)
+ provider.setToken(token2, SECONDARY_DISPLAY)
+
+ assertThat(provider.getToken(DEFAULT_DISPLAY)).isEqualTo(token1)
+ assertThat(provider.getToken(SECONDARY_DISPLAY)).isEqualTo(token2)
+
+ provider.removeToken(DEFAULT_DISPLAY)
+
+ assertThat(provider.getToken(DEFAULT_DISPLAY)).isNull()
+ assertThat(provider.getToken(SECONDARY_DISPLAY)).isEqualTo(token2)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
index 9f09e3f57927..4dcf669f4d25 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
@@ -20,6 +20,7 @@ import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.testing.AndroidTestingRunner
import android.view.Display.DEFAULT_DISPLAY
+import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_CLOSE
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
@@ -177,4 +178,70 @@ class DesksTransitionObserverTest : ShellTestCase() {
assertThat(repository.getActiveDeskId(DEFAULT_DISPLAY)).isEqualTo(deskId)
assertThat(repository.getActiveTaskIdsInDesk(deskId)).contains(task.taskId)
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onTransitionReady_deactivateDesk_updatesRepository() {
+ val transition = Binder()
+ val deskChange = Change(mock(), mock())
+ whenever(mockDesksOrganizer.isDeskChange(deskChange, deskId = 5)).thenReturn(true)
+ val deactivateTransition = DeskTransition.DeactivateDesk(transition, deskId = 5)
+ repository.addDesk(DEFAULT_DISPLAY, deskId = 5)
+ repository.setActiveDesk(DEFAULT_DISPLAY, deskId = 5)
+
+ observer.addPendingTransition(deactivateTransition)
+ observer.onTransitionReady(
+ transition = transition,
+ info = TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0).apply { addChange(deskChange) },
+ )
+
+ assertThat(repository.getActiveDeskId(DEFAULT_DISPLAY)).isNull()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onTransitionReady_deactivateDeskWithExitingTask_updatesRepository() {
+ val transition = Binder()
+ val exitingTask = createFreeformTask(DEFAULT_DISPLAY)
+ val exitingTaskChange = Change(mock(), mock()).apply { taskInfo = exitingTask }
+ whenever(mockDesksOrganizer.getDeskAtEnd(exitingTaskChange)).thenReturn(null)
+ val deactivateTransition = DeskTransition.DeactivateDesk(transition, deskId = 5)
+ repository.addDesk(DEFAULT_DISPLAY, deskId = 5)
+ repository.setActiveDesk(DEFAULT_DISPLAY, deskId = 5)
+ repository.addTaskToDesk(
+ displayId = DEFAULT_DISPLAY,
+ deskId = 5,
+ taskId = exitingTask.taskId,
+ isVisible = true,
+ )
+ assertThat(repository.isActiveTaskInDesk(deskId = 5, taskId = exitingTask.taskId)).isTrue()
+
+ observer.addPendingTransition(deactivateTransition)
+ observer.onTransitionReady(
+ transition = transition,
+ info =
+ TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0).apply {
+ addChange(exitingTaskChange)
+ },
+ )
+
+ assertThat(repository.isActiveTaskInDesk(deskId = 5, taskId = exitingTask.taskId)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onTransitionReady_deactivateDeskWithoutVisibleChange_updatesRepository() {
+ val transition = Binder()
+ val deactivateTransition = DeskTransition.DeactivateDesk(transition, deskId = 5)
+ repository.addDesk(DEFAULT_DISPLAY, deskId = 5)
+ repository.setActiveDesk(DEFAULT_DISPLAY, deskId = 5)
+
+ observer.addPendingTransition(deactivateTransition)
+ observer.onTransitionReady(
+ transition = transition,
+ info = TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0),
+ )
+
+ assertThat(repository.getActiveDeskId(DEFAULT_DISPLAY)).isNull()
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt
index 4d4b15389eca..8b10ca1a2a70 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt
@@ -23,11 +23,13 @@ import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp
+import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
+import com.android.wm.shell.desktopmode.multidesks.RootTaskDesksOrganizer.DeskRoot
import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellInit
import com.google.common.truth.Truth.assertThat
@@ -104,54 +106,45 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
@Test
fun testOnTaskVanished_removesRoot() {
- val callback = FakeOnCreateCallback()
- organizer.createDesk(Display.DEFAULT_DISPLAY, callback)
- val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
- organizer.onTaskAppeared(freeformRoot, SurfaceControl())
+ val desk = createDesk()
- organizer.onTaskVanished(freeformRoot)
+ organizer.onTaskVanished(desk.taskInfo)
- assertThat(organizer.roots.contains(freeformRoot.taskId)).isFalse()
+ assertThat(organizer.roots.contains(desk.deskId)).isFalse()
}
@Test
fun testDesktopWindowAppearsInDesk() {
- organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
- val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
- organizer.onTaskAppeared(freeformRoot, SurfaceControl())
- val child = createFreeformTask().apply { parentTaskId = freeformRoot.taskId }
+ val desk = createDesk()
+ val child = createFreeformTask().apply { parentTaskId = desk.deskId }
organizer.onTaskAppeared(child, SurfaceControl())
- assertThat(organizer.roots[freeformRoot.taskId].children).contains(child.taskId)
+ assertThat(desk.children).contains(child.taskId)
}
@Test
fun testDesktopWindowDisappearsFromDesk() {
- organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
- val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
- organizer.onTaskAppeared(freeformRoot, SurfaceControl())
- val child = createFreeformTask().apply { parentTaskId = freeformRoot.taskId }
+ val desk = createDesk()
+ val child = createFreeformTask().apply { parentTaskId = desk.deskId }
organizer.onTaskAppeared(child, SurfaceControl())
organizer.onTaskVanished(child)
- assertThat(organizer.roots[freeformRoot.taskId].children).doesNotContain(child.taskId)
+ assertThat(desk.children).doesNotContain(child.taskId)
}
@Test
fun testRemoveDesk() {
- organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
- val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
- organizer.onTaskAppeared(freeformRoot, SurfaceControl())
+ val desk = createDesk()
val wct = WindowContainerTransaction()
- organizer.removeDesk(wct, freeformRoot.taskId)
+ organizer.removeDesk(wct, desk.deskId)
assertThat(
wct.hierarchyOps.any { hop ->
hop.type == HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK &&
- hop.container == freeformRoot.token.asBinder()
+ hop.container == desk.taskInfo.token.asBinder()
}
)
.isTrue()
@@ -167,25 +160,23 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
@Test
fun testActivateDesk() {
- organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
- val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
- organizer.onTaskAppeared(freeformRoot, SurfaceControl())
+ val desk = createDesk()
val wct = WindowContainerTransaction()
- organizer.activateDesk(wct, freeformRoot.taskId)
+ organizer.activateDesk(wct, desk.deskId)
assertThat(
wct.hierarchyOps.any { hop ->
hop.type == HierarchyOp.HIERARCHY_OP_TYPE_REORDER &&
hop.toTop &&
- hop.container == freeformRoot.token.asBinder()
+ hop.container == desk.taskInfo.token.asBinder()
}
)
.isTrue()
assertThat(
wct.hierarchyOps.any { hop ->
hop.type == HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT &&
- hop.container == freeformRoot.token.asBinder()
+ hop.container == desk.taskInfo.token.asBinder()
}
)
.isTrue()
@@ -201,20 +192,18 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
@Test
fun testMoveTaskToDesk() {
- organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
- val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
- organizer.onTaskAppeared(freeformRoot, SurfaceControl())
+ val desk = createDesk()
val desktopTask = createFreeformTask().apply { parentTaskId = -1 }
val wct = WindowContainerTransaction()
- organizer.moveTaskToDesk(wct, freeformRoot.taskId, desktopTask)
+ organizer.moveTaskToDesk(wct, desk.deskId, desktopTask)
assertThat(
wct.hierarchyOps.any { hop ->
hop.isReparent &&
hop.toTop &&
hop.container == desktopTask.token.asBinder() &&
- hop.newParent == freeformRoot.token.asBinder()
+ hop.newParent == desk.taskInfo.token.asBinder()
}
)
.isTrue()
@@ -240,17 +229,15 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
@Test
fun testGetDeskAtEnd() {
- organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
- val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
- organizer.onTaskAppeared(freeformRoot, SurfaceControl())
+ val desk = createDesk()
- val task = createFreeformTask().apply { parentTaskId = freeformRoot.taskId }
+ val task = createFreeformTask().apply { parentTaskId = desk.deskId }
val endDesk =
organizer.getDeskAtEnd(
TransitionInfo.Change(task.token, SurfaceControl()).apply { taskInfo = task }
)
- assertThat(endDesk).isEqualTo(freeformRoot.taskId)
+ assertThat(endDesk).isEqualTo(desk.deskId)
}
@Test
@@ -273,6 +260,47 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
assertThat(isActive).isTrue()
}
+ @Test
+ fun deactivateDesk_clearsLaunchRoot() {
+ val wct = WindowContainerTransaction()
+ val desk = createDesk()
+ organizer.activateDesk(wct, desk.deskId)
+
+ organizer.deactivateDesk(wct, desk.deskId)
+
+ assertThat(
+ wct.hierarchyOps.any { hop ->
+ hop.type == HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT &&
+ hop.container == desk.taskInfo.token.asBinder() &&
+ hop.windowingModes == null &&
+ hop.activityTypes == null
+ }
+ )
+ .isTrue()
+ }
+
+ @Test
+ fun isDeskChange() {
+ val desk = createDesk()
+
+ assertThat(
+ organizer.isDeskChange(
+ TransitionInfo.Change(desk.taskInfo.token, desk.leash).apply {
+ taskInfo = desk.taskInfo
+ },
+ desk.deskId,
+ )
+ )
+ .isTrue()
+ }
+
+ private fun createDesk(): DeskRoot {
+ organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
+ val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
+ organizer.onTaskAppeared(freeformRoot, SurfaceControl())
+ return organizer.roots[freeformRoot.taskId]
+ }
+
private class FakeOnCreateCallback : DesksOrganizer.OnCreateCallback {
var deskId: Int? = null
val created: Boolean
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
index 8e0381e4f933..0c1952910d1a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.pip2.phone;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
@@ -26,6 +27,7 @@ import static org.mockito.kotlin.MatchersKt.eq;
import static org.mockito.kotlin.VerificationKt.times;
import static org.mockito.kotlin.VerificationKt.verify;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Matrix;
@@ -44,15 +46,19 @@ import com.android.wm.shell.common.pip.PipDesktopState;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
/**
* Unit test against {@link PipScheduler}
*/
@@ -77,6 +83,8 @@ public class PipSchedulerTest {
@Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;
@Mock private SurfaceControl.Transaction mMockTransaction;
@Mock private PipAlphaAnimator mMockAlphaAnimator;
+ @Mock private SplitScreenController mMockSplitScreenController;
+
@Captor private ArgumentCaptor<Runnable> mRunnableArgumentCaptor;
@Captor private ArgumentCaptor<WindowContainerTransaction> mWctArgumentCaptor;
@@ -93,7 +101,8 @@ public class PipSchedulerTest {
.thenReturn(mMockTransaction);
mPipScheduler = new PipScheduler(mMockContext, mMockPipBoundsState, mMockMainExecutor,
- mMockPipTransitionState, mMockPipDesktopState);
+ mMockPipTransitionState, Optional.of(mMockSplitScreenController),
+ mMockPipDesktopState);
mPipScheduler.setPipTransitionController(mMockPipTransitionController);
mPipScheduler.setSurfaceControlTransactionFactory(mMockFactory);
mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, startTx, finishTx, direction) ->
@@ -119,12 +128,18 @@ public class PipSchedulerTest {
assertNotNull(mRunnableArgumentCaptor.getValue());
mRunnableArgumentCaptor.getValue().run();
- verify(mMockPipTransitionController, never()).startExpandTransition(any());
+ verify(mMockPipTransitionController, never()).startExpandTransition(any(), anyBoolean());
}
@Test
- public void scheduleExitPipViaExpand_exitTransitionCalled() {
+ public void scheduleExitPipViaExpand_noSplit_expandTransitionCalled() {
setMockPipTaskToken();
+ ActivityManager.RunningTaskInfo pipTaskInfo = getTaskInfoWithLastParentBeforePip(1);
+ when(mMockPipTransitionState.getPipTaskInfo()).thenReturn(pipTaskInfo);
+
+ // Make sure task with the id = 1 isn't in split-screen.
+ when(mMockSplitScreenController.isTaskInSplitScreen(
+ ArgumentMatchers.eq(1))).thenReturn(false);
mPipScheduler.scheduleExitPipViaExpand();
@@ -132,7 +147,29 @@ public class PipSchedulerTest {
assertNotNull(mRunnableArgumentCaptor.getValue());
mRunnableArgumentCaptor.getValue().run();
- verify(mMockPipTransitionController, times(1)).startExpandTransition(any());
+ verify(mMockPipTransitionController, times(1)).startExpandTransition(any(), anyBoolean());
+ }
+
+ @Test
+ public void scheduleExitPipViaExpand_lastParentInSplit_prepareSplitAndExpand() {
+ setMockPipTaskToken();
+ ActivityManager.RunningTaskInfo pipTaskInfo = getTaskInfoWithLastParentBeforePip(1);
+ when(mMockPipTransitionState.getPipTaskInfo()).thenReturn(pipTaskInfo);
+
+ // Make sure task with the id = 1 is in split-screen.
+ when(mMockSplitScreenController.isTaskInSplitScreen(
+ ArgumentMatchers.eq(1))).thenReturn(true);
+
+ mPipScheduler.scheduleExitPipViaExpand();
+
+ verify(mMockMainExecutor, times(1)).execute(mRunnableArgumentCaptor.capture());
+ assertNotNull(mRunnableArgumentCaptor.getValue());
+ mRunnableArgumentCaptor.getValue().run();
+
+ // We need to both prepare the split screen with the last parent and start expanding.
+ verify(mMockSplitScreenController,
+ times(1)).prepareEnterSplitScreen(any(), any(), anyInt());
+ verify(mMockPipTransitionController, times(1)).startExpandTransition(any(), anyBoolean());
}
@Test
@@ -259,4 +296,10 @@ public class PipSchedulerTest {
private void setMockPipTaskToken() {
when(mMockPipTransitionState.getPipTaskToken()).thenReturn(mMockPipTaskToken);
}
+
+ private ActivityManager.RunningTaskInfo getTaskInfoWithLastParentBeforePip(int lastParentId) {
+ final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ taskInfo.lastParentTaskIdBeforePip = lastParentId;
+ return taskInfo;
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTouchStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTouchStateTest.java
new file mode 100644
index 000000000000..2e389b7dd151
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTouchStateTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 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.wm.shell.pip2.phone;
+
+import static android.view.MotionEvent.ACTION_BUTTON_PRESS;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestShellExecutor;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class PipTouchStateTest extends ShellTestCase {
+
+ private PipTouchState mTouchState;
+ private CountDownLatch mDoubleTapCallbackTriggeredLatch;
+ private CountDownLatch mHoverExitCallbackTriggeredLatch;
+ private TestShellExecutor mMainExecutor;
+
+ @Before
+ public void setUp() throws Exception {
+ mMainExecutor = new TestShellExecutor();
+ mDoubleTapCallbackTriggeredLatch = new CountDownLatch(1);
+ mHoverExitCallbackTriggeredLatch = new CountDownLatch(1);
+ mTouchState = new PipTouchState(ViewConfiguration.get(getContext()),
+ mDoubleTapCallbackTriggeredLatch::countDown,
+ mHoverExitCallbackTriggeredLatch::countDown,
+ mMainExecutor);
+ assertFalse(mTouchState.isDoubleTap());
+ assertFalse(mTouchState.isWaitingForDoubleTap());
+ }
+
+ @Test
+ public void testDoubleTapLongSingleTap_notDoubleTapAndNotWaiting() {
+ final long currentTime = SystemClock.uptimeMillis();
+
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN, currentTime, 0, 0));
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_UP,
+ currentTime + PipTouchState.DOUBLE_TAP_TIMEOUT + 10, 0, 0));
+ assertFalse(mTouchState.isDoubleTap());
+ assertFalse(mTouchState.isWaitingForDoubleTap());
+ assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == -1);
+ }
+
+ @Test
+ public void testDoubleTapTimeout_timeoutCallbackCalled() throws Exception {
+ final long currentTime = SystemClock.uptimeMillis();
+
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN, currentTime, 0, 0));
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_UP,
+ currentTime + PipTouchState.DOUBLE_TAP_TIMEOUT - 10, 0, 0));
+ assertFalse(mTouchState.isDoubleTap());
+ assertTrue(mTouchState.isWaitingForDoubleTap());
+
+ assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == 10);
+ mTouchState.scheduleDoubleTapTimeoutCallback();
+
+ mMainExecutor.flushAll();
+ assertTrue(mDoubleTapCallbackTriggeredLatch.getCount() == 0);
+ }
+
+ @Test
+ public void testDoubleTapDrag_doubleTapCanceled() {
+ final long currentTime = SystemClock.uptimeMillis();
+
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN, currentTime, 0, 0));
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_MOVE, currentTime + 10, 500, 500));
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_UP, currentTime + 20, 500, 500));
+ assertTrue(mTouchState.isDragging());
+ assertFalse(mTouchState.isDoubleTap());
+ assertFalse(mTouchState.isWaitingForDoubleTap());
+ assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == -1);
+ }
+
+ @Test
+ public void testDoubleTap_doubleTapRegistered() {
+ final long currentTime = SystemClock.uptimeMillis();
+
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN, currentTime, 0, 0));
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_UP, currentTime + 10, 0, 0));
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN,
+ currentTime + PipTouchState.DOUBLE_TAP_TIMEOUT - 20, 0, 0));
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_UP,
+ currentTime + PipTouchState.DOUBLE_TAP_TIMEOUT - 10, 0, 0));
+ assertTrue(mTouchState.isDoubleTap());
+ assertFalse(mTouchState.isWaitingForDoubleTap());
+ assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == -1);
+ }
+
+ @Test
+ public void testHoverExitTimeout_timeoutCallbackCalled() throws Exception {
+ mTouchState.scheduleHoverExitTimeoutCallback();
+ mMainExecutor.flushAll();
+ assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 0);
+ }
+
+ @Test
+ public void testHoverExitTimeout_timeoutCallbackNotCalled() throws Exception {
+ mTouchState.scheduleHoverExitTimeoutCallback();
+ assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 1);
+ }
+
+ @Test
+ public void testHoverExitTimeout_timeoutCallbackNotCalled_ifButtonPress() throws Exception {
+ mTouchState.scheduleHoverExitTimeoutCallback();
+ mTouchState.onTouchEvent(createMotionEvent(ACTION_BUTTON_PRESS, SystemClock.uptimeMillis(),
+ 0, 0));
+ mMainExecutor.flushAll();
+ assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 1);
+ }
+
+ private MotionEvent createMotionEvent(int action, long eventTime, float x, float y) {
+ return MotionEvent.obtain(0, eventTime, action, x, y, 0);
+ }
+
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandlerTest.java
new file mode 100644
index 000000000000..2a22842eda1a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandlerTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.pip2.phone.transition;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.TRANSIT_CHANGE;
+
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
+
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.kotlin.VerificationKt.times;
+import static org.mockito.kotlin.VerificationKt.verify;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.PictureInPictureParams;
+import android.app.WindowConfiguration;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+import com.android.wm.shell.pip2.animation.PipExpandAnimator;
+import com.android.wm.shell.pip2.phone.PipTransitionState;
+import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.transition.TransitionInfoBuilder;
+import com.android.wm.shell.util.StubTransaction;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Optional;
+
+/**
+ * Unit test against {@link PipExpandHandler}
+ */
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+public class PipExpandHandlerTest {
+ @Mock private Context mMockContext;
+ @Mock private PipBoundsState mMockPipBoundsState;
+ @Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
+ @Mock private PipTransitionState mMockPipTransitionState;
+ @Mock private PipDisplayLayoutState mMockPipDisplayLayoutState;
+ @Mock private SplitScreenController mMockSplitScreenController;
+
+ @Mock private IBinder mMockTransitionToken;
+ @Mock private TransitionRequestInfo mMockRequestInfo;
+ @Mock private StubTransaction mStartT;
+ @Mock private StubTransaction mFinishT;
+ @Mock private SurfaceControl mPipLeash;
+
+ @Mock private PipExpandAnimator mMockPipExpandAnimator;
+
+ @Surface.Rotation
+ private static final int DISPLAY_ROTATION = Surface.ROTATION_0;
+
+ private static final float SNAP_FRACTION = 1.5f;
+ private static final Rect PIP_BOUNDS = new Rect(0, 0, 100, 100);
+ private static final Rect DISPLAY_BOUNDS = new Rect(0, 0, 1000, 1000);
+ private static final Rect RIGHT_HALF_DISPLAY_BOUNDS = new Rect(500, 0, 1000, 1000);
+
+ private PipExpandHandler mPipExpandHandler;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mMockPipBoundsState.getBounds()).thenReturn(PIP_BOUNDS);
+ when(mMockPipBoundsAlgorithm.getSnapFraction(eq(PIP_BOUNDS))).thenReturn(SNAP_FRACTION);
+ when(mMockPipDisplayLayoutState.getRotation()).thenReturn(DISPLAY_ROTATION);
+
+ mPipExpandHandler = new PipExpandHandler(mMockContext, mMockPipBoundsState,
+ mMockPipBoundsAlgorithm, mMockPipTransitionState, mMockPipDisplayLayoutState,
+ Optional.of(mMockSplitScreenController));
+ mPipExpandHandler.setPipExpandAnimatorSupplier((context, leash, startTransaction,
+ finishTransaction, baseBounds, startBounds, endBounds,
+ sourceRectHint, rotation) -> mMockPipExpandAnimator);
+ }
+
+ @Test
+ public void handleRequest_returnNull() {
+ // All expand from PiP transitions are started in Shell, so handleRequest shouldn't be
+ // returning any non-null WCT
+ WindowContainerTransaction wct = mPipExpandHandler.handleRequest(
+ mMockTransitionToken, mMockRequestInfo);
+ assertNull(wct);
+ }
+
+ @Test
+ public void startAnimation_transitExit_startExpandAnimator() {
+ final ActivityManager.RunningTaskInfo pipTaskInfo = createPipTaskInfo(
+ 1, WINDOWING_MODE_FULLSCREEN, new PictureInPictureParams.Builder().build());
+
+ final TransitionInfo info = getExpandFromPipTransitionInfo(
+ TRANSIT_EXIT_PIP, pipTaskInfo, null /* lastParent */, false /* toSplit */);
+ final WindowContainerToken pipToken = pipTaskInfo.getToken();
+ when(mMockPipTransitionState.getPipTaskToken()).thenReturn(pipToken);
+
+ mPipExpandHandler.startAnimation(mMockTransitionToken, info, mStartT, mFinishT,
+ (wct) -> {});
+
+ verify(mMockPipExpandAnimator, times(1)).start();
+ verify(mMockPipBoundsState, times(1)).saveReentryState(SNAP_FRACTION);
+ }
+
+ @Test
+ public void startAnimation_transitExitToSplit_startExpandAnimator() {
+ // The task info of the task that was pinned while we were in PiP.
+ final WindowContainerToken pipToken = createPipTaskInfo(1, WINDOWING_MODE_FULLSCREEN,
+ new PictureInPictureParams.Builder().build()).getToken();
+ when(mMockPipTransitionState.getPipTaskToken()).thenReturn(pipToken);
+
+ // Change representing the ActivityRecord we are animating in the multi-activity PiP case;
+ // make sure change's taskInfo=null as this is an activity, but let lastParent be PiP token.
+ final TransitionInfo info = getExpandFromPipTransitionInfo(
+ TRANSIT_EXIT_PIP_TO_SPLIT, null /* taskInfo */, pipToken, true /* toSplit */);
+
+ mPipExpandHandler.startAnimation(mMockTransitionToken, info, mStartT, mFinishT,
+ (wct) -> {});
+
+ verify(mMockSplitScreenController, times(1)).finishEnterSplitScreen(eq(mFinishT));
+ verify(mMockPipExpandAnimator, times(1)).start();
+ verify(mMockPipBoundsState, times(1)).saveReentryState(SNAP_FRACTION);
+ }
+
+ private TransitionInfo getExpandFromPipTransitionInfo(@WindowManager.TransitionType int type,
+ @Nullable ActivityManager.RunningTaskInfo pipTaskInfo,
+ @Nullable WindowContainerToken lastParent, boolean toSplit) {
+ final TransitionInfo info = new TransitionInfoBuilder(type)
+ .addChange(TRANSIT_CHANGE, pipTaskInfo).build();
+ final TransitionInfo.Change pipChange = info.getChanges().getFirst();
+ pipChange.setRotation(DISPLAY_ROTATION,
+ WindowConfiguration.ROTATION_UNDEFINED);
+ pipChange.setStartAbsBounds(PIP_BOUNDS);
+ pipChange.setEndAbsBounds(toSplit ? RIGHT_HALF_DISPLAY_BOUNDS : DISPLAY_BOUNDS);
+ pipChange.setLeash(mPipLeash);
+ pipChange.setLastParent(lastParent);
+ return info;
+ }
+
+ private static ActivityManager.RunningTaskInfo createPipTaskInfo(int taskId,
+ int windowingMode, PictureInPictureParams params) {
+ ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ taskInfo.taskId = taskId;
+ taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
+ taskInfo.token = mock(WindowContainerToken.class);
+ taskInfo.baseIntent = mock(Intent.class);
+ taskInfo.pictureInPictureParams = params;
+ return taskInfo;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 5028479b6ace..a546b3ea7d8f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -107,6 +107,7 @@ import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class RecentTasksControllerTest extends ShellTestCase {
+ private static final String SYSTEM_UI_PACKAGE_NAME = "com.android.systemui";
@Mock
private Context mContext;
@@ -582,6 +583,19 @@ public class RecentTasksControllerTest extends ShellTestCase {
@Test
@EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS})
+ public void onTaskAdded_orDesktopWallpaperActivity_doesNotTriggerOnRunningTaskAppeared()
+ throws Exception {
+ RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+
+ mRecentTasksControllerReal.onTaskAdded(taskInfo);
+
+ verify(mRecentTasksListener, never()).onRunningTaskAppeared(any());
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS})
public void taskWindowingModeChanged_desktopRunningAppsEnabled_triggersOnRunningTaskChanged()
throws Exception {
mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
@@ -593,6 +607,19 @@ public class RecentTasksControllerTest extends ShellTestCase {
}
@Test
+ @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS})
+ public void taskInfoChanged_forDesktopWallpaperActivity_doesNotTriggerOnRunningTaskChanged()
+ throws Exception {
+ RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+
+ mRecentTasksControllerReal.onTaskRunningInfoChanged(taskInfo);
+
+ verify(mRecentTasksListener, never()).onRunningTaskChanged(any());
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS)
public void
@@ -619,6 +646,20 @@ public class RecentTasksControllerTest extends ShellTestCase {
verify(mRecentTasksListener).onRunningTaskVanished(taskInfo);
}
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS})
+ public void onTaskRemoved_forDesktopWallpaperActivity_doesNotTriggerOnRunningTaskVanished()
+ throws Exception {
+ RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+
+ mRecentTasksControllerReal.onTaskRemoved(taskInfo);
+
+ verify(mRecentTasksListener, never()).onRunningTaskVanished(any());
+ }
+
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS)
@@ -659,6 +700,18 @@ public class RecentTasksControllerTest extends ShellTestCase {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ public void onDesktopWallpaperActivityMovedToFront_doesNotTriggerOnTaskMovedToFront()
+ throws Exception {
+ RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10);
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+
+ mRecentTasksControllerReal.onTaskMovedToFrontThroughTransition(taskInfo);
+
+ verify(mRecentTasksListener, never()).onTaskMovedToFront(any());
+ }
+
+ @Test
public void getNullSplitBoundsNonSplitTask() {
SplitBounds sb = mRecentTasksController.getSplitBoundsForTaskId(3);
assertNull("splitBounds should be null for non-split task", sb);
@@ -829,16 +882,25 @@ public class RecentTasksControllerTest extends ShellTestCase {
* Helper to create a running task with a given task id.
*/
private RunningTaskInfo makeRunningTaskInfo(int taskId) {
+ return makeRunningTaskInfo(taskId, new ComponentName("com." + taskId, "Activity" + taskId));
+ }
+
+ private RunningTaskInfo makeRunningTaskInfo(int taskId, ComponentName intentComponent) {
RunningTaskInfo info = new RunningTaskInfo();
info.taskId = taskId;
info.realActivity = new ComponentName("testPackage", "testClass");
Intent intent = new Intent();
- intent.setComponent(new ComponentName("com." + taskId, "Activity" + taskId));
+ intent.setComponent(intentComponent);
info.baseIntent = intent;
info.lastNonFullscreenBounds = new Rect();
return info;
}
+ private RunningTaskInfo makeDesktopWallpaperActivityTaskInfo(int taskId) {
+ return makeRunningTaskInfo(taskId, new ComponentName(SYSTEM_UI_PACKAGE_NAME,
+ DesktopWallpaperActivity.class.getName()));
+ }
+
/**
* Helper to set the raw task list on the controller.
*/
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java
index 439be9155b26..fd5e567f69ed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java
@@ -34,6 +34,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -293,6 +294,31 @@ public class RecentsTransitionHandlerTest extends ShellTestCase {
@Test
@EnableFlags(FLAG_ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX)
+ public void testMerge_openingTasks_callsOnTasksAppeared() throws Exception {
+ final IRecentsAnimationRunner animationRunner = mock(IRecentsAnimationRunner.class);
+ TransitionInfo mergeTransitionInfo = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN, new TestRunningTaskInfoBuilder().build())
+ .build();
+ final IBinder transition = startRecentsTransition(/* synthetic= */ false, animationRunner);
+ SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
+ mRecentsTransitionHandler.startAnimation(
+ transition, createTransitionInfo(), new StubTransaction(), new StubTransaction(),
+ mock(Transitions.TransitionFinishCallback.class));
+
+ mRecentsTransitionHandler.findController(transition).merge(
+ mergeTransitionInfo,
+ new StubTransaction(),
+ finishT,
+ transition,
+ mock(Transitions.TransitionFinishCallback.class));
+ mMainExecutor.flushAll();
+
+ verify(animationRunner).onTasksAppeared(
+ /* appearedTargets= */ any(), eq(mergeTransitionInfo));
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX)
public void testMergeAndFinish_openingFreeformTasks_setsCornerRadius() {
ActivityManager.RunningTaskInfo freeformTask =
new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt
index efb91c5fbfda..180a6915b45f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt
@@ -16,23 +16,33 @@
package com.android.wm.shell.shared.bubbles
+import android.content.Context
import android.graphics.Rect
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.animation.AnimatorTestRule
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFails
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import kotlin.test.assertFails
/** Unit tests for [DropTargetManager]. */
@SmallTest
@RunWith(AndroidJUnit4::class)
class DropTargetManagerTest {
+ @get:Rule val animatorTestRule = AnimatorTestRule()
+
+ private val context = getApplicationContext<Context>()
private lateinit var dropTargetManager: DropTargetManager
private lateinit var dragZoneChangedListener: FakeDragZoneChangedListener
- private val dropTarget = Rect(0, 0, 0, 0)
+ private lateinit var container: FrameLayout
// create 3 drop zones that are horizontally next to each other
// -------------------------------------------------
@@ -43,15 +53,20 @@ class DropTargetManagerTest {
// | | | |
// -------------------------------------------------
private val bubbleLeftDragZone =
- DragZone.Bubble.Left(bounds = Rect(0, 0, 100, 100), dropTarget = dropTarget)
+ DragZone.Bubble.Left(bounds = Rect(0, 0, 100, 100), dropTarget = Rect(0, 0, 50, 200))
private val dismissDragZone = DragZone.Dismiss(bounds = Rect(100, 0, 200, 100))
private val bubbleRightDragZone =
- DragZone.Bubble.Right(bounds = Rect(200, 0, 300, 100), dropTarget = dropTarget)
+ DragZone.Bubble.Right(bounds = Rect(200, 0, 300, 100), dropTarget = Rect(200, 0, 280, 150))
+
+ private val dropTargetView: View
+ get() = container.getChildAt(0)
@Before
fun setUp() {
+ container = FrameLayout(context)
dragZoneChangedListener = FakeDragZoneChangedListener()
- dropTargetManager = DropTargetManager(isLayoutRtl = false, dragZoneChangedListener)
+ dropTargetManager =
+ DropTargetManager(context, container, isLayoutRtl = false, dragZoneChangedListener)
}
@Test
@@ -79,17 +94,21 @@ class DropTargetManagerTest {
DraggedObject.Bubble(BubbleBarLocation.LEFT),
listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone)
)
- dropTargetManager.onDragUpdated(
- bubbleRightDragZone.bounds.centerX(),
- bubbleRightDragZone.bounds.centerY()
- )
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleRightDragZone.bounds.centerX(),
+ bubbleRightDragZone.bounds.centerY()
+ )
+ }
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleLeftDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(bubbleRightDragZone)
- dropTargetManager.onDragUpdated(
- dismissDragZone.bounds.centerX(),
- dismissDragZone.bounds.centerY()
- )
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ dismissDragZone.bounds.centerX(),
+ dismissDragZone.bounds.centerY()
+ )
+ }
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleRightDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(dismissDragZone)
}
@@ -100,10 +119,12 @@ class DropTargetManagerTest {
DraggedObject.Bubble(BubbleBarLocation.LEFT),
listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone)
)
- dropTargetManager.onDragUpdated(
- bubbleLeftDragZone.bounds.centerX(),
- bubbleLeftDragZone.bounds.centerY()
- )
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleLeftDragZone.bounds.centerX(),
+ bubbleLeftDragZone.bounds.centerY()
+ )
+ }
assertThat(dragZoneChangedListener.fromDragZone).isNull()
assertThat(dragZoneChangedListener.toDragZone).isNull()
}
@@ -118,7 +139,9 @@ class DropTargetManagerTest {
val pointY = 200
assertThat(bubbleLeftDragZone.contains(pointX, pointY)).isFalse()
assertThat(bubbleRightDragZone.contains(pointX, pointY)).isFalse()
- dropTargetManager.onDragUpdated(pointX, pointY)
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(pointX, pointY)
+ }
assertThat(dragZoneChangedListener.fromDragZone).isNull()
assertThat(dragZoneChangedListener.toDragZone).isNull()
}
@@ -135,27 +158,30 @@ class DropTargetManagerTest {
// drag to a point that is within both the bubble right zone and split zone
val (pointX, pointY) =
- Pair(
- bubbleRightDragZone.bounds.centerX(),
- bubbleRightDragZone.bounds.centerY()
- )
+ Pair(bubbleRightDragZone.bounds.centerX(), bubbleRightDragZone.bounds.centerY())
assertThat(splitDragZone.contains(pointX, pointY)).isTrue()
- dropTargetManager.onDragUpdated(pointX, pointY)
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(pointX, pointY)
+ }
// verify we dragged to the bubble right zone because that has higher priority than split
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleLeftDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(bubbleRightDragZone)
- dropTargetManager.onDragUpdated(
- bubbleRightDragZone.bounds.centerX(),
- 150 // below the bubble and dismiss drag zones but within split
- )
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleRightDragZone.bounds.centerX(),
+ 150 // below the bubble and dismiss drag zones but within split
+ )
+ }
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleRightDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(splitDragZone)
val (dismissPointX, dismissPointY) =
Pair(dismissDragZone.bounds.centerX(), dismissDragZone.bounds.centerY())
assertThat(splitDragZone.contains(dismissPointX, dismissPointY)).isTrue()
- dropTargetManager.onDragUpdated(dismissPointX, dismissPointY)
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(dismissPointX, dismissPointY)
+ }
assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(splitDragZone)
assertThat(dragZoneChangedListener.toDragZone).isEqualTo(dismissDragZone)
}
@@ -166,7 +192,9 @@ class DropTargetManagerTest {
DraggedObject.Bubble(BubbleBarLocation.LEFT),
listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone)
)
- dropTargetManager.onDragEnded()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragEnded()
+ }
dropTargetManager.onDragUpdated(
bubbleRightDragZone.bounds.centerX(),
bubbleRightDragZone.bounds.centerY()
@@ -175,6 +203,129 @@ class DropTargetManagerTest {
assertThat(dragZoneChangedListener.toDragZone).isNull()
}
+ @Test
+ fun onDragStarted_dropTargetAddedToContainer() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(bubbleLeftDragZone, bubbleRightDragZone)
+ )
+ assertThat(container.childCount).isEqualTo(1)
+ assertThat(dropTargetView.alpha).isEqualTo(0)
+ }
+
+ @Test
+ fun onDragEnded_dropTargetRemovedFromContainer() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(bubbleLeftDragZone, bubbleRightDragZone)
+ )
+ assertThat(container.childCount).isEqualTo(1)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragEnded()
+ animatorTestRule.advanceTimeBy(250)
+ }
+ assertThat(container.childCount).isEqualTo(0)
+ }
+
+ @Test
+ fun startNewDrag_beforeDropTargetRemoved() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(bubbleLeftDragZone, bubbleRightDragZone)
+ )
+ assertThat(container.childCount).isEqualTo(1)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragEnded()
+ // advance the timer by 100ms so the animation doesn't complete
+ animatorTestRule.advanceTimeBy(100)
+ }
+ assertThat(container.childCount).isEqualTo(1)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(bubbleLeftDragZone, bubbleRightDragZone)
+ )
+ }
+ assertThat(container.childCount).isEqualTo(1)
+ }
+
+ @Test
+ fun updateDragZone_withDropTarget_dropTargetUpdated() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(dismissDragZone, bubbleLeftDragZone, bubbleRightDragZone)
+ )
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleRightDragZone.bounds.centerX(),
+ bubbleRightDragZone.bounds.centerY()
+ )
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ assertThat(dropTargetView.alpha).isEqualTo(1)
+ verifyDropTargetPosition(bubbleRightDragZone.dropTarget)
+ }
+
+ @Test
+ fun updateDragZone_withoutDropTarget_dropTargetHidden() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(dismissDragZone, bubbleLeftDragZone, bubbleRightDragZone)
+ )
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ dismissDragZone.bounds.centerX(),
+ dismissDragZone.bounds.centerY()
+ )
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ assertThat(dropTargetView.alpha).isEqualTo(0)
+ }
+
+ @Test
+ fun updateDragZone_betweenZonesWithDropTarget_dropTargetUpdated() {
+ dropTargetManager.onDragStarted(
+ DraggedObject.Bubble(BubbleBarLocation.LEFT),
+ listOf(dismissDragZone, bubbleLeftDragZone, bubbleRightDragZone)
+ )
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleRightDragZone.bounds.centerX(),
+ bubbleRightDragZone.bounds.centerY()
+ )
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ assertThat(dropTargetView.alpha).isEqualTo(1)
+ verifyDropTargetPosition(bubbleRightDragZone.dropTarget)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ dropTargetManager.onDragUpdated(
+ bubbleLeftDragZone.bounds.centerX(),
+ bubbleLeftDragZone.bounds.centerY()
+ )
+ animatorTestRule.advanceTimeBy(250)
+ }
+
+ assertThat(dropTargetView.alpha).isEqualTo(1)
+ verifyDropTargetPosition(bubbleLeftDragZone.dropTarget)
+ }
+
+ private fun verifyDropTargetPosition(rect: Rect) {
+ assertThat(dropTargetView.scaleX).isEqualTo(rect.width())
+ assertThat(dropTargetView.scaleY).isEqualTo(rect.height())
+ assertThat(dropTargetView.translationX).isEqualTo(rect.exactCenterX())
+ assertThat(dropTargetView.translationY).isEqualTo(rect.exactCenterY())
+ }
+
private class FakeDragZoneChangedListener : DropTargetManager.DragZoneChangedListener {
var initialDragZone: DragZone? = null
var fromDragZone: DragZone? = null
@@ -183,6 +334,7 @@ class DropTargetManagerTest {
override fun onInitialDragZoneSet(dragZone: DragZone) {
initialDragZone = dragZone
}
+
override fun onDragZoneChanged(from: DragZone, to: DragZone) {
fromDragZone = from
toDragZone = to
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
index 391d46287498..4082ffd4ac0a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
@@ -22,8 +22,6 @@ import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.Presubmit
import android.platform.test.flag.junit.SetFlagsRule
-import android.provider.Settings
-import android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES
import android.window.DesktopModeFlags
import androidx.test.filters.SmallTest
import com.android.internal.R
@@ -63,14 +61,12 @@ class DesktopModeStatusTest : ShellTestCase() {
doReturn(context.contentResolver).whenever(mockContext).contentResolver
resetDesktopModeFlagsCache()
resetEnforceDeviceRestriction()
- resetFlagOverride()
}
@After
fun tearDown() {
resetDesktopModeFlagsCache()
resetEnforceDeviceRestriction()
- resetFlagOverride()
}
@DisableFlags(
@@ -157,23 +153,40 @@ class DesktopModeStatusTest : ShellTestCase() {
}
@Test
- fun isInternalDisplayEligibleToHostDesktops_configDEModeOn_returnsTrue() {
+ fun isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktop_returnsTrue() {
+ doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
- assertThat(DesktopModeStatus.isInternalDisplayEligibleToHostDesktops(mockContext)).isTrue()
+ assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isTrue()
+ }
+
+ @Test
+ fun isDeviceEligibleForDesktopMode_configDEModeOffAndIntDispHostsDesktop_returnsFalse() {
+ doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
+ doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
+
+ assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
+ }
+
+ @Test
+ fun isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktopOff_returnsFalse() {
+ doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
+ doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
+
+ assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
}
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
@Test
fun isInternalDisplayEligibleToHostDesktops_supportFlagOff_returnsFalse() {
- assertThat(DesktopModeStatus.isInternalDisplayEligibleToHostDesktops(mockContext)).isFalse()
+ assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
}
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
@Test
fun isInternalDisplayEligibleToHostDesktops_supportFlagOn_returnsFalse() {
- assertThat(DesktopModeStatus.isInternalDisplayEligibleToHostDesktops(mockContext)).isFalse()
+ assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
}
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
@@ -183,7 +196,7 @@ class DesktopModeStatusTest : ShellTestCase() {
eq(R.bool.config_isDesktopModeDevOptionSupported)
)
- assertThat(DesktopModeStatus.isInternalDisplayEligibleToHostDesktops(mockContext)).isTrue()
+ assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isTrue()
}
@DisableFlags(Flags.FLAG_SHOW_DESKTOP_EXPERIENCE_DEV_OPTION)
@@ -229,18 +242,11 @@ class DesktopModeStatusTest : ShellTestCase() {
cachedToggleOverride.set(null, null)
}
- private fun resetFlagOverride() {
- Settings.Global.putString(
- context.contentResolver,
- DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, null
- )
- }
-
private fun setFlagOverride(override: DesktopModeFlags.ToggleOverride) {
- Settings.Global.putInt(
- context.contentResolver,
- DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, override.setting
- )
+ val cachedToggleOverride =
+ DesktopModeFlags::class.java.getDeclaredField("sCachedToggleOverride")
+ cachedToggleOverride.isAccessible = true
+ cachedToggleOverride.set(null, override)
}
private fun setDeviceEligibleForDesktopMode(eligible: Boolean) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index da41a23f066c..d8d45c02b364 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -484,7 +484,6 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest
eq(SnapPosition.LEFT),
eq(ResizeTrigger.SNAP_LEFT_MENU),
eq(InputMethod.UNKNOWN_INPUT_METHOD),
- eq(decor)
)
}
@@ -520,7 +519,6 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest
eq(SnapPosition.LEFT),
eq(ResizeTrigger.SNAP_LEFT_MENU),
eq(InputMethod.UNKNOWN_INPUT_METHOD),
- eq(decor),
)
}
@@ -542,7 +540,6 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest
eq(decor.mTaskInfo), any(), eq(currentBounds), eq(SnapPosition.LEFT),
eq(ResizeTrigger.MAXIMIZE_BUTTON),
eq(InputMethod.UNKNOWN_INPUT_METHOD),
- eq(decor),
)
}
@@ -562,7 +559,6 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest
eq(SnapPosition.RIGHT),
eq(ResizeTrigger.SNAP_RIGHT_MENU),
eq(InputMethod.UNKNOWN_INPUT_METHOD),
- eq(decor),
)
}
@@ -598,7 +594,6 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest
eq(SnapPosition.RIGHT),
eq(ResizeTrigger.SNAP_RIGHT_MENU),
eq(InputMethod.UNKNOWN_INPUT_METHOD),
- eq(decor),
)
}
@@ -620,7 +615,6 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest
eq(decor.mTaskInfo), any(), eq(currentBounds), eq(SnapPosition.RIGHT),
eq(ResizeTrigger.MAXIMIZE_BUTTON),
eq(InputMethod.UNKNOWN_INPUT_METHOD),
- eq(decor),
)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
index e40034b09f39..8cccdb2b6120 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
@@ -81,6 +81,7 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopM
import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier
+import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder
import org.junit.After
import org.mockito.Mockito
@@ -147,6 +148,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() {
protected val mockCaptionHandleRepository = mock<WindowDecorCaptionHandleRepository>()
protected val mockDesktopRepository: DesktopRepository = mock<DesktopRepository>()
protected val mockRecentsTransitionHandler = mock<RecentsTransitionHandler>()
+ protected val mockTilingWindowDecoration = mock<DesktopTilingDecorViewModel>()
protected val motionEvent = mock<MotionEvent>()
private val displayLayout = mock<DisplayLayout>()
private val display = mock<Display>()
@@ -226,6 +228,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() {
mock<WindowDecorTaskResourceLoader>(),
mockRecentsTransitionHandler,
desktopModeCompatPolicy,
+ mockTilingWindowDecoration,
)
desktopModeWindowDecorViewModel.setSplitScreenController(mockSplitScreenController)
whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 71c821dd9b71..c4f70ac2297f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -120,6 +120,7 @@ import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
+import kotlin.jvm.functions.Function2;
import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.MainCoroutineDispatcher;
@@ -998,8 +999,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
createMaximizeMenu(decoration);
- verify(menu).show(anyBoolean(), anyInt(), anyBoolean(), anyBoolean(), any(), any(), any(),
- any(), mOnMaxMenuHoverChangeListener.capture(), any());
+ verify(menu).show(anyBoolean(), anyBoolean(), anyBoolean(), any(), any(), any(), any(),
+ mOnMaxMenuHoverChangeListener.capture(), any());
assertTrue(decoration.isMaximizeMenuActive());
}
@@ -1011,8 +1012,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
new FakeMaximizeMenuFactory(menu));
decoration.setAppHeaderMaximizeButtonHovered(false);
createMaximizeMenu(decoration);
- verify(menu).show(anyBoolean(), anyInt(), anyBoolean(), anyBoolean(), any(), any(), any(),
- any(), mOnMaxMenuHoverChangeListener.capture(), any());
+ verify(menu).show(anyBoolean(), anyBoolean(), anyBoolean(), any(), any(), any(), any(),
+ mOnMaxMenuHoverChangeListener.capture(), any());
mOnMaxMenuHoverChangeListener.getValue().invoke(false);
@@ -1050,8 +1051,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo,
new FakeMaximizeMenuFactory(menu));
createMaximizeMenu(decoration);
- verify(menu).show(anyBoolean(), anyInt(), anyBoolean(), anyBoolean(), any(), any(), any(),
- any(), mOnMaxMenuHoverChangeListener.capture(), any());
+ verify(menu).show(anyBoolean(), anyBoolean(), anyBoolean(), any(), any(), any(), any(),
+ mOnMaxMenuHoverChangeListener.capture(), any());
mOnMaxMenuHoverChangeListener.getValue().invoke(true);
@@ -1065,8 +1066,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo,
new FakeMaximizeMenuFactory(menu));
createMaximizeMenu(decoration);
- verify(menu).show(anyBoolean(), anyInt(), anyBoolean(), anyBoolean(), any(), any(), any(),
- any(), mOnMaxMenuHoverChangeListener.capture(), any());
+ verify(menu).show(anyBoolean(), anyBoolean(), anyBoolean(), any(), any(), any(), any(),
+ mOnMaxMenuHoverChangeListener.capture(), any());
decoration.setAppHeaderMaximizeButtonHovered(true);
@@ -1086,7 +1087,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
verify(menu).show(
anyBoolean(),
- anyInt(),
/* showImmersiveOption= */ eq(true),
anyBoolean(),
any(),
@@ -1111,7 +1111,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
verify(menu).show(
anyBoolean(),
- anyInt(),
/* showImmersiveOption= */ eq(false),
anyBoolean(),
any(),
@@ -1136,7 +1135,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
verify(menu).show(
anyBoolean(),
- anyInt(),
anyBoolean(),
/* showSnapOptions= */ eq(true),
any(),
@@ -1161,7 +1159,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
verify(menu).show(
anyBoolean(),
- anyInt(),
anyBoolean(),
/* showSnapOptions= */ eq(false),
any(),
@@ -1766,7 +1763,9 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
@NonNull RootTaskDisplayAreaOrganizer rootTdaOrganizer,
@NonNull DisplayController displayController,
@NonNull ActivityManager.RunningTaskInfo taskInfo,
- @NonNull Context decorWindowContext, @NonNull PointF menuPosition,
+ @NonNull Context decorWindowContext,
+ @NonNull Function2<? super Integer,? super Integer,? extends PointF>
+ positionSupplier,
@NonNull Supplier<SurfaceControl.Transaction> transactionSupplier) {
return mMaximizeMenu;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
index 63babc5e1c3c..937938df82c8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt
@@ -249,6 +249,25 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() {
}
@Test
+ fun testDragResize_movesTaskOnSameDisplay_noPxDpConversion() = runOnUiThread {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED,
+ DISPLAY_ID_0,
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat(),
+ )
+
+ taskPositioner.onDragPositioningEnd(
+ DISPLAY_ID_0,
+ STARTING_BOUNDS.left.toFloat() + 70,
+ STARTING_BOUNDS.top.toFloat() + 20,
+ )
+
+ verify(spyDisplayLayout0, never()).localPxToGlobalDp(any(), any())
+ verify(spyDisplayLayout0, never()).globalDpToLocalPx(any(), any())
+ }
+
+ @Test
fun testDragResize_movesTaskToNewDisplay() = runOnUiThread {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_UNDEFINED,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index aa1f82e3e4d8..af0162334440 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -40,6 +40,7 @@ import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
@@ -386,6 +387,49 @@ public class WindowDecorationTests extends ShellTestCase {
verify(mMockWindowDecorViewHost).updateView(same(mMockView), any(), any(), any(), any());
}
+
+ @Test
+ public void testReinflateViewsOnFontScaleChange() {
+ final Display defaultDisplay = mock(Display.class);
+ doReturn(defaultDisplay).when(mMockDisplayController)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+
+ final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+ .setVisible(true)
+ .setDisplayId(Display.DEFAULT_DISPLAY)
+ .build();
+ final TestWindowDecoration windowDecor = spy(createWindowDecoration(taskInfo));
+ windowDecor.relayout(taskInfo, true /* hasGlobalFocus */, Region.obtain());
+ clearInvocations(windowDecor);
+ final ActivityManager.RunningTaskInfo taskInfo2 = new TestRunningTaskInfoBuilder()
+ .setVisible(true)
+ .setDisplayId(Display.DEFAULT_DISPLAY)
+ .build();
+ taskInfo2.configuration.fontScale = taskInfo.configuration.fontScale + 1;
+ windowDecor.relayout(taskInfo2, true /* hasGlobalFocus */, Region.obtain());
+ // WindowDecoration#releaseViews should be called since the font scale has changed.
+ verify(windowDecor).releaseViews(any());
+ }
+
+ @Test
+ public void testViewNotReinflatedWhenFontScaleNotChanged() {
+ final Display defaultDisplay = mock(Display.class);
+ doReturn(defaultDisplay).when(mMockDisplayController)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+
+ final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+ .setVisible(true)
+ .setDisplayId(Display.DEFAULT_DISPLAY)
+ .build();
+ final TestWindowDecoration windowDecor = spy(createWindowDecoration(taskInfo));
+ windowDecor.relayout(taskInfo, true /* hasGlobalFocus */, Region.obtain());
+ clearInvocations(windowDecor);
+ windowDecor.relayout(taskInfo, true /* hasGlobalFocus */, Region.obtain());
+ // WindowDecoration#releaseViews should be called since task info (and therefore the
+ // fontScale) has not changed.
+ verify(windowDecor, never()).releaseViews(any());
+ }
+
@Test
public void testAddViewHostViewContainer() {
final Display defaultDisplay = mock(Display.class);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt
index d99a4825e580..c86730ed1dc7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt
@@ -20,6 +20,7 @@ import android.testing.TestableLooper
import android.view.SurfaceControl
import android.view.View
import android.view.WindowManager
+import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTestCase
import com.google.common.truth.Truth.assertThat
@@ -30,6 +31,9 @@ import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.never
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
@@ -47,24 +51,46 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() {
fun update_differentView_replacesView() = runTest {
val view = View(context)
val lp = WindowManager.LayoutParams()
- val reusableVH = createReusableViewHost()
- reusableVH.updateView(view, lp, context.resources.configuration, null)
+ val rootView = FrameLayout(context)
+ val reusableVH = createReusableViewHost(rootView)
+ reusableVH.updateView(view, lp, context.resources.configuration)
- assertThat(reusableVH.rootView.childCount).isEqualTo(1)
- assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(view)
+ assertThat(rootView.childCount).isEqualTo(1)
+ assertThat(rootView.getChildAt(0)).isEqualTo(view)
val newView = View(context)
val newLp = WindowManager.LayoutParams()
- reusableVH.updateView(newView, newLp, context.resources.configuration, null)
+ reusableVH.updateView(newView, newLp, context.resources.configuration)
- assertThat(reusableVH.rootView.childCount).isEqualTo(1)
- assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(newView)
+ assertThat(rootView.childCount).isEqualTo(1)
+ assertThat(rootView.getChildAt(0)).isEqualTo(newView)
+ }
+
+ @Test
+ fun update_sameView_doesNotReplaceView() = runTest {
+ val view = View(context)
+ val lp = WindowManager.LayoutParams()
+ val spyRootView = spy(FrameLayout(context))
+ val reusableVH = createReusableViewHost(spyRootView)
+ reusableVH.updateView(view, lp, context.resources.configuration)
+
+ verify(spyRootView, times(1)).removeAllViews()
+ assertThat(spyRootView.childCount).isEqualTo(1)
+ assertThat(spyRootView.getChildAt(0)).isEqualTo(view)
+
+ reusableVH.updateView(view, lp, context.resources.configuration)
+
+ clearInvocations(spyRootView)
+ verify(spyRootView, never()).removeAllViews()
+ assertThat(spyRootView.childCount).isEqualTo(1)
+ assertThat(spyRootView.getChildAt(0)).isEqualTo(view)
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun updateView_clearsPendingAsyncJob() = runTest {
- val reusableVH = createReusableViewHost()
+ val rootView = FrameLayout(context)
+ val reusableVH = createReusableViewHost(rootView)
val asyncView = View(context)
val syncView = View(context)
val asyncAttrs = WindowManager.LayoutParams(100, 100)
@@ -83,7 +109,6 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() {
view = syncView,
attrs = syncAttrs,
configuration = context.resources.configuration,
- onDrawTransaction = null,
)
// Would run coroutine if it hadn't been cancelled.
@@ -91,7 +116,7 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() {
assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
// View host view/attrs should match the ones from the sync call.
- assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(syncView)
+ assertThat(rootView.getChildAt(0)).isEqualTo(syncView)
assertThat(reusableVH.view()!!.layoutParams.width).isEqualTo(syncAttrs.width)
}
@@ -118,7 +143,8 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() {
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun updateViewAsync_clearsPendingAsyncJob() = runTest {
- val reusableVH = createReusableViewHost()
+ val rootView = FrameLayout(context)
+ val reusableVH = createReusableViewHost(rootView)
val view = View(context)
reusableVH.updateViewAsync(
@@ -136,7 +162,7 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() {
advanceUntilIdle()
assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
- assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(otherView)
+ assertThat(rootView.getChildAt(0)).isEqualTo(otherView)
}
@Test
@@ -148,7 +174,6 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() {
view = view,
attrs = WindowManager.LayoutParams(100, 100),
configuration = context.resources.configuration,
- onDrawTransaction = null,
)
val t = mock(SurfaceControl.Transaction::class.java)
@@ -159,19 +184,23 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() {
@Test
fun warmUp_addsRootView() = runTest {
- val reusableVH = createReusableViewHost().apply { warmUp() }
+ val rootView = FrameLayout(context)
+ val reusableVH = createReusableViewHost(rootView).apply { warmUp() }
assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
- assertThat(reusableVH.view()).isEqualTo(reusableVH.rootView)
+ assertThat(reusableVH.view()).isEqualTo(rootView)
}
- private fun CoroutineScope.createReusableViewHost() =
+ private fun CoroutineScope.createReusableViewHost(
+ rootView: FrameLayout = FrameLayout(context)
+ ) =
ReusableWindowDecorViewHost(
context = context,
mainScope = this,
display = context.display,
id = 1,
viewHostAdapter = spy(SurfaceControlViewHostAdapter(context, context.display)),
+ rootView
)
private fun ReusableWindowDecorViewHost.view(): View? = viewHostAdapter.viewHost?.view
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index dbb891455ddd..e693fcfd3918 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -162,10 +162,13 @@ const std::string& ApkAssets::GetDebugName() const {
return assets_provider_->GetDebugName();
}
-bool ApkAssets::IsUpToDate() const {
+UpToDate ApkAssets::IsUpToDate() const {
// Loaders are invalidated by the app, not the system, so assume they are up to date.
- return IsLoader() || ((!loaded_idmap_ || loaded_idmap_->IsUpToDate())
- && assets_provider_->IsUpToDate());
+ if (IsLoader()) {
+ return UpToDate::Always;
+ }
+ const auto idmap_res = loaded_idmap_ ? loaded_idmap_->IsUpToDate() : UpToDate::Always;
+ return combine(idmap_res, [this] { return assets_provider_->IsUpToDate(); });
}
} // namespace android
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 0fa31c7a832e..f5e10d94452f 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -1467,8 +1467,6 @@ base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceId(
}
const StringPiece16 kAttr16 = u"attr";
- const static std::u16string kAttrPrivate16 = u"^attr-private";
-
for (const PackageGroup& package_group : package_groups_) {
for (const ConfiguredPackage& package_impl : package_group.packages_) {
const LoadedPackage* package = package_impl.loaded_package_;
@@ -1480,12 +1478,13 @@ base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceId(
base::expected<uint32_t, NullOrIOError> resid = package->FindEntryByName(type16, entry16);
if (UNLIKELY(IsIOError(resid))) {
return base::unexpected(resid.error());
- }
+ }
if (!resid.has_value() && kAttr16 == type16) {
// Private attributes in libraries (such as the framework) are sometimes encoded
// under the type '^attr-private' in order to leave the ID space of public 'attr'
// free for future additions. Check '^attr-private' for the same name.
+ const static std::u16string kAttrPrivate16 = u"^attr-private";
resid = package->FindEntryByName(kAttrPrivate16, entry16);
}
diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp
index 2d3c06506a1f..808509120462 100644
--- a/libs/androidfw/AssetsProvider.cpp
+++ b/libs/androidfw/AssetsProvider.cpp
@@ -24,9 +24,27 @@
#include <ziparchive/zip_archive.h>
namespace android {
-namespace {
-constexpr const char* kEmptyDebugString = "<empty>";
-} // namespace
+
+static constexpr std::string_view kEmptyDebugString = "<empty>";
+
+std::unique_ptr<AssetsProvider> AssetsProvider::CreateWithOverride(
+ std::unique_ptr<AssetsProvider> provider, std::unique_ptr<AssetsProvider> override) {
+ if (provider == nullptr) {
+ return {};
+ }
+ if (override == nullptr) {
+ return provider;
+ }
+ return MultiAssetsProvider::Create(std::move(override), std::move(provider));
+}
+
+std::unique_ptr<AssetsProvider> AssetsProvider::CreateFromNullable(
+ std::unique_ptr<AssetsProvider> nullable) {
+ if (nullable) {
+ return nullable;
+ }
+ return EmptyAssetsProvider::Create();
+}
std::unique_ptr<Asset> AssetsProvider::Open(const std::string& path, Asset::AccessMode mode,
bool* file_exists) const {
@@ -86,11 +104,9 @@ void ZipAssetsProvider::ZipCloser::operator()(ZipArchive* a) const {
}
ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path,
- package_property_t flags, time_t last_mod_time)
- : zip_handle_(handle),
- name_(std::move(path)),
- flags_(flags),
- last_mod_time_(last_mod_time) {}
+ package_property_t flags, ModDate last_mod_time)
+ : zip_handle_(handle), name_(std::move(path)), flags_(flags), last_mod_time_(last_mod_time) {
+}
std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path,
package_property_t flags,
@@ -104,10 +120,10 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path,
return {};
}
- struct stat sb{.st_mtime = -1};
+ ModDate mod_date = kInvalidModDate;
// Skip all up-to-date checks if the file won't ever change.
- if (!isReadonlyFilesystem(path.c_str())) {
- if ((released_fd < 0 ? stat(path.c_str(), &sb) : fstat(released_fd, &sb)) < 0) {
+ if (isKnownWritablePath(path.c_str()) || !isReadonlyFilesystem(GetFileDescriptor(handle))) {
+ if (mod_date = getFileModDate(GetFileDescriptor(handle)); mod_date == kInvalidModDate) {
// Stat requires execute permissions on all directories path to the file. If the process does
// not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
// always have to return true.
@@ -116,7 +132,7 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path,
}
return std::unique_ptr<ZipAssetsProvider>(
- new ZipAssetsProvider(handle, PathOrDebugName::Path(std::move(path)), flags, sb.st_mtime));
+ new ZipAssetsProvider(handle, PathOrDebugName::Path(std::move(path)), flags, mod_date));
}
std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd,
@@ -137,10 +153,10 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd,
return {};
}
- struct stat sb{.st_mtime = -1};
+ ModDate mod_date = kInvalidModDate;
// Skip all up-to-date checks if the file won't ever change.
if (!isReadonlyFilesystem(released_fd)) {
- if (fstat(released_fd, &sb) < 0) {
+ if (mod_date = getFileModDate(released_fd); mod_date == kInvalidModDate) {
// Stat requires execute permissions on all directories path to the file. If the process does
// not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
// always have to return true.
@@ -150,7 +166,7 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd,
}
return std::unique_ptr<ZipAssetsProvider>(new ZipAssetsProvider(
- handle, PathOrDebugName::DebugName(std::move(friendly_name)), flags, sb.st_mtime));
+ handle, PathOrDebugName::DebugName(std::move(friendly_name)), flags, mod_date));
}
std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path,
@@ -282,21 +298,16 @@ const std::string& ZipAssetsProvider::GetDebugName() const {
return name_.GetDebugName();
}
-bool ZipAssetsProvider::IsUpToDate() const {
- if (last_mod_time_ == -1) {
- return true;
+UpToDate ZipAssetsProvider::IsUpToDate() const {
+ if (last_mod_time_ == kInvalidModDate) {
+ return UpToDate::Always;
}
- struct stat sb{};
- if (fstat(GetFileDescriptor(zip_handle_.get()), &sb) < 0) {
- // If fstat fails on the zip archive, return true so the zip archive the resource system does
- // attempt to refresh the ApkAsset.
- return true;
- }
- return last_mod_time_ == sb.st_mtime;
+ return fromBool(last_mod_time_ == getFileModDate(GetFileDescriptor(zip_handle_.get())));
}
-DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, time_t last_mod_time)
- : dir_(std::move(path)), last_mod_time_(last_mod_time) {}
+DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, ModDate last_mod_time)
+ : dir_(std::move(path)), last_mod_time_(last_mod_time) {
+}
std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::string path) {
struct stat sb;
@@ -317,7 +328,7 @@ std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::st
const bool isReadonly = isReadonlyFilesystem(path.c_str());
return std::unique_ptr<DirectoryAssetsProvider>(
- new DirectoryAssetsProvider(std::move(path), isReadonly ? -1 : sb.st_mtime));
+ new DirectoryAssetsProvider(std::move(path), isReadonly ? kInvalidModDate : getModDate(sb)));
}
std::unique_ptr<Asset> DirectoryAssetsProvider::OpenInternal(const std::string& path,
@@ -346,17 +357,11 @@ const std::string& DirectoryAssetsProvider::GetDebugName() const {
return dir_;
}
-bool DirectoryAssetsProvider::IsUpToDate() const {
- if (last_mod_time_ == -1) {
- return true;
+UpToDate DirectoryAssetsProvider::IsUpToDate() const {
+ if (last_mod_time_ == kInvalidModDate) {
+ return UpToDate::Always;
}
- struct stat sb;
- if (stat(dir_.c_str(), &sb) < 0) {
- // If stat fails on the zip archive, return true so the zip archive the resource system does
- // attempt to refresh the ApkAsset.
- return true;
- }
- return last_mod_time_ == sb.st_mtime;
+ return fromBool(last_mod_time_ == getFileModDate(dir_.c_str()));
}
MultiAssetsProvider::MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& primary,
@@ -397,8 +402,8 @@ const std::string& MultiAssetsProvider::GetDebugName() const {
return debug_name_;
}
-bool MultiAssetsProvider::IsUpToDate() const {
- return primary_->IsUpToDate() && secondary_->IsUpToDate();
+UpToDate MultiAssetsProvider::IsUpToDate() const {
+ return combine(primary_->IsUpToDate(), [this] { return secondary_->IsUpToDate(); });
}
EmptyAssetsProvider::EmptyAssetsProvider(std::optional<std::string>&& path) :
@@ -438,12 +443,12 @@ const std::string& EmptyAssetsProvider::GetDebugName() const {
if (path_.has_value()) {
return *path_;
}
- const static std::string kEmpty = kEmptyDebugString;
+ constexpr static std::string kEmpty{kEmptyDebugString};
return kEmpty;
}
-bool EmptyAssetsProvider::IsUpToDate() const {
- return true;
+UpToDate EmptyAssetsProvider::IsUpToDate() const {
+ return UpToDate::Always;
}
} // namespace android
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index 095be57a5dc8..f0ef97e5bdcc 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -22,9 +22,10 @@
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "android-base/utf8.h"
-#include "androidfw/misc.h"
+#include "androidfw/AssetManager.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/Util.h"
+#include "androidfw/misc.h"
#include "utils/ByteOrder.h"
#include "utils/Trace.h"
@@ -280,11 +281,16 @@ LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* head
configurations_(configs),
overlay_entries_(overlay_entries),
string_pool_(std::move(string_pool)),
- idmap_fd_(
- android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)),
overlay_apk_path_(overlay_apk_path),
target_apk_path_(target_apk_path),
- idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) {
+ idmap_last_mod_time_(kInvalidModDate) {
+ if (!isReadonlyFilesystem(std::string(overlay_apk_path_).c_str()) ||
+ !(target_apk_path_ == AssetManager::TARGET_APK_PATH ||
+ isReadonlyFilesystem(std::string(target_apk_path_).c_str()))) {
+ idmap_fd_.reset(
+ android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH));
+ idmap_last_mod_time_ = getFileModDate(idmap_fd_);
+ }
}
std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) {
@@ -405,8 +411,11 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie
std::move(idmap_string_pool),*overlay_path, *target_path));
}
-bool LoadedIdmap::IsUpToDate() const {
- return idmap_last_mod_time_ == getFileModDate(idmap_fd_.get());
+UpToDate LoadedIdmap::IsUpToDate() const {
+ if (idmap_last_mod_time_ == kInvalidModDate) {
+ return UpToDate::Always;
+ }
+ return fromBool(idmap_last_mod_time_ == getFileModDate(idmap_fd_.get()));
}
} // namespace android
diff --git a/libs/androidfw/LocaleDataLookup.cpp b/libs/androidfw/LocaleDataLookup.cpp
index ea9e9a2d4280..9aacdcb9ca92 100644
--- a/libs/androidfw/LocaleDataLookup.cpp
+++ b/libs/androidfw/LocaleDataLookup.cpp
@@ -14871,12 +14871,22 @@ static uint32_t findLatnParent(uint32_t packed_lang_region) {
case 0x656E4154u: // en-AT -> en-150
case 0x656E4245u: // en-BE -> en-150
case 0x656E4348u: // en-CH -> en-150
+ case 0x656E435Au: // en-CZ -> en-150
case 0x656E4445u: // en-DE -> en-150
case 0x656E444Bu: // en-DK -> en-150
+ case 0x656E4553u: // en-ES -> en-150
case 0x656E4649u: // en-FI -> en-150
+ case 0x656E4652u: // en-FR -> en-150
+ case 0x656E4855u: // en-HU -> en-150
+ case 0x656E4954u: // en-IT -> en-150
case 0x656E4E4Cu: // en-NL -> en-150
+ case 0x656E4E4Fu: // en-NO -> en-150
+ case 0x656E504Cu: // en-PL -> en-150
+ case 0x656E5054u: // en-PT -> en-150
+ case 0x656E524Fu: // en-RO -> en-150
case 0x656E5345u: // en-SE -> en-150
case 0x656E5349u: // en-SI -> en-150
+ case 0x656E534Bu: // en-SK -> en-150
return 0x656E80A1u;
case 0x65734152u: // es-AR -> es-419
case 0x6573424Fu: // es-BO -> es-419
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 978bc768cd3d..a18c5f5f92f6 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -152,12 +152,11 @@ static void fill9patchOffsets(Res_png_9patch* patch) {
patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t));
}
-void Res_value::copyFrom_dtoh(const Res_value& src)
-{
- size = dtohs(src.size);
- res0 = src.res0;
- dataType = src.dataType;
- data = dtohl(src.data);
+void Res_value::copyFrom_dtoh_slow(const Res_value& src) {
+ size = dtohs(src.size);
+ res0 = src.res0;
+ dataType = src.dataType;
+ data = dtohl(src.data);
}
void Res_png_9patch::deviceToFile()
@@ -2035,16 +2034,6 @@ status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
// --------------------------------------------------------------------
// --------------------------------------------------------------------
-void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) {
- const size_t size = dtohl(o.size);
- if (size >= sizeof(ResTable_config)) {
- *this = o;
- } else {
- memcpy(this, &o, size);
- memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
- }
-}
-
/* static */ size_t unpackLanguageOrRegion(const char in[2], const char base,
char out[4]) {
if (in[0] & 0x80) {
@@ -2109,34 +2098,33 @@ size_t ResTable_config::unpackRegion(char region[4]) const {
return unpackLanguageOrRegion(this->country, '0', region);
}
-
-void ResTable_config::copyFromDtoH(const ResTable_config& o) {
- copyFromDeviceNoSwap(o);
- size = sizeof(ResTable_config);
- mcc = dtohs(mcc);
- mnc = dtohs(mnc);
- density = dtohs(density);
- screenWidth = dtohs(screenWidth);
- screenHeight = dtohs(screenHeight);
- sdkVersion = dtohs(sdkVersion);
- minorVersion = dtohs(minorVersion);
- smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
- screenWidthDp = dtohs(screenWidthDp);
- screenHeightDp = dtohs(screenHeightDp);
-}
-
-void ResTable_config::swapHtoD() {
- size = htodl(size);
- mcc = htods(mcc);
- mnc = htods(mnc);
- density = htods(density);
- screenWidth = htods(screenWidth);
- screenHeight = htods(screenHeight);
- sdkVersion = htods(sdkVersion);
- minorVersion = htods(minorVersion);
- smallestScreenWidthDp = htods(smallestScreenWidthDp);
- screenWidthDp = htods(screenWidthDp);
- screenHeightDp = htods(screenHeightDp);
+void ResTable_config::copyFromDtoH_slow(const ResTable_config& o) {
+ copyFromDeviceNoSwap(o);
+ size = sizeof(ResTable_config);
+ mcc = dtohs(mcc);
+ mnc = dtohs(mnc);
+ density = dtohs(density);
+ screenWidth = dtohs(screenWidth);
+ screenHeight = dtohs(screenHeight);
+ sdkVersion = dtohs(sdkVersion);
+ minorVersion = dtohs(minorVersion);
+ smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
+ screenWidthDp = dtohs(screenWidthDp);
+ screenHeightDp = dtohs(screenHeightDp);
+}
+
+void ResTable_config::swapHtoD_slow() {
+ size = htodl(size);
+ mcc = htods(mcc);
+ mnc = htods(mnc);
+ density = htods(density);
+ screenWidth = htods(screenWidth);
+ screenHeight = htods(screenHeight);
+ sdkVersion = htods(sdkVersion);
+ minorVersion = htods(minorVersion);
+ smallestScreenWidthDp = htods(smallestScreenWidthDp);
+ screenWidthDp = htods(screenWidthDp);
+ screenHeightDp = htods(screenHeightDp);
}
/* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) {
@@ -2149,7 +2137,7 @@ void ResTable_config::swapHtoD() {
// systems should happen very infrequently (if at all.)
// The comparison code relies on memcmp low-level optimizations that make it
// more efficient than strncmp.
- const char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'};
+ static constexpr char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'};
const char *lScript = l.localeScriptWasComputed ? emptyScript : l.localeScript;
const char *rScript = r.localeScriptWasComputed ? emptyScript : r.localeScript;
diff --git a/libs/androidfw/Util.cpp b/libs/androidfw/Util.cpp
index be55fe8b4bb6..86c459fb4647 100644
--- a/libs/androidfw/Util.cpp
+++ b/libs/androidfw/Util.cpp
@@ -32,13 +32,18 @@ namespace android {
namespace util {
void ReadUtf16StringFromDevice(const uint16_t* src, size_t len, std::string* out) {
- char buf[5];
- while (*src && len != 0) {
- char16_t c = static_cast<char16_t>(dtohs(*src));
- utf16_to_utf8(&c, 1, buf, sizeof(buf));
- out->append(buf, strlen(buf));
- ++src;
- --len;
+ static constexpr bool kDeviceEndiannessSame = dtohs(0x1001) == 0x1001;
+ if constexpr (kDeviceEndiannessSame) {
+ *out = Utf16ToUtf8({(const char16_t*)src, strnlen16((const char16_t*)src, len)});
+ } else {
+ char buf[5];
+ while (*src && len != 0) {
+ char16_t c = static_cast<char16_t>(dtohs(*src));
+ utf16_to_utf8(&c, 1, buf, sizeof(buf));
+ out->append(buf, strlen(buf));
+ ++src;
+ --len;
+ }
}
}
@@ -63,8 +68,10 @@ std::string Utf16ToUtf8(StringPiece16 utf16) {
}
std::string utf8;
- utf8.resize(utf8_length);
- utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin(), utf8_length + 1);
+ utf8.resize_and_overwrite(utf8_length, [&utf16](char* data, size_t size) {
+ utf16_to_utf8(utf16.data(), utf16.length(), data, size + 1);
+ return size;
+ });
return utf8;
}
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 231808beb718..3f6f4661f2f7 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -116,7 +116,7 @@ class ApkAssets : public RefBase {
return resources_asset_ != nullptr && resources_asset_->isAllocated();
}
- bool IsUpToDate() const;
+ UpToDate IsUpToDate() const;
// DANGER!
// This is a destructive method that rips the assets provider out of ApkAssets object.
diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h
index d33c325ff369..037f684f5b78 100644
--- a/libs/androidfw/include/androidfw/AssetsProvider.h
+++ b/libs/androidfw/include/androidfw/AssetsProvider.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROIDFW_ASSETSPROVIDER_H
-#define ANDROIDFW_ASSETSPROVIDER_H
+#pragma once
#include <memory>
#include <string>
@@ -37,6 +36,12 @@ namespace android {
struct AssetsProvider {
static constexpr off64_t kUnknownLength = -1;
+ static std::unique_ptr<AssetsProvider> CreateWithOverride(
+ std::unique_ptr<AssetsProvider> provider, std::unique_ptr<AssetsProvider> override);
+
+ static std::unique_ptr<AssetsProvider> CreateFromNullable(
+ std::unique_ptr<AssetsProvider> nullable);
+
// Opens a file for reading. If `file_exists` is not null, it will be set to `true` if the file
// exists. This is useful for determining if the file exists but was unable to be opened due to
// an I/O error.
@@ -58,7 +63,7 @@ struct AssetsProvider {
WARN_UNUSED virtual const std::string& GetDebugName() const = 0;
// Returns whether the interface provides the most recent version of its files.
- WARN_UNUSED virtual bool IsUpToDate() const = 0;
+ WARN_UNUSED virtual UpToDate IsUpToDate() const = 0;
// Creates an Asset from a file on disk.
static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
@@ -95,7 +100,7 @@ struct ZipAssetsProvider : public AssetsProvider {
WARN_UNUSED std::optional<std::string_view> GetPath() const override;
WARN_UNUSED const std::string& GetDebugName() const override;
- WARN_UNUSED bool IsUpToDate() const override;
+ WARN_UNUSED UpToDate IsUpToDate() const override;
WARN_UNUSED std::optional<uint32_t> GetCrc(std::string_view path) const;
~ZipAssetsProvider() override = default;
@@ -106,7 +111,7 @@ struct ZipAssetsProvider : public AssetsProvider {
private:
struct PathOrDebugName;
ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path, package_property_t flags,
- time_t last_mod_time);
+ ModDate last_mod_time);
struct PathOrDebugName {
static PathOrDebugName Path(std::string value) {
@@ -135,7 +140,7 @@ struct ZipAssetsProvider : public AssetsProvider {
std::unique_ptr<ZipArchive, ZipCloser> zip_handle_;
PathOrDebugName name_;
package_property_t flags_;
- time_t last_mod_time_;
+ ModDate last_mod_time_;
};
// Supplies assets from a root directory.
@@ -147,7 +152,7 @@ struct DirectoryAssetsProvider : public AssetsProvider {
WARN_UNUSED std::optional<std::string_view> GetPath() const override;
WARN_UNUSED const std::string& GetDebugName() const override;
- WARN_UNUSED bool IsUpToDate() const override;
+ WARN_UNUSED UpToDate IsUpToDate() const override;
~DirectoryAssetsProvider() override = default;
protected:
@@ -156,9 +161,9 @@ struct DirectoryAssetsProvider : public AssetsProvider {
bool* file_exists) const override;
private:
- explicit DirectoryAssetsProvider(std::string&& path, time_t last_mod_time);
+ explicit DirectoryAssetsProvider(std::string&& path, ModDate last_mod_time);
std::string dir_;
- time_t last_mod_time_;
+ ModDate last_mod_time_;
};
// Supplies assets from a `primary` asset provider and falls back to supplying assets from the
@@ -172,7 +177,7 @@ struct MultiAssetsProvider : public AssetsProvider {
WARN_UNUSED std::optional<std::string_view> GetPath() const override;
WARN_UNUSED const std::string& GetDebugName() const override;
- WARN_UNUSED bool IsUpToDate() const override;
+ WARN_UNUSED UpToDate IsUpToDate() const override;
~MultiAssetsProvider() override = default;
protected:
@@ -199,7 +204,7 @@ struct EmptyAssetsProvider : public AssetsProvider {
WARN_UNUSED std::optional<std::string_view> GetPath() const override;
WARN_UNUSED const std::string& GetDebugName() const override;
- WARN_UNUSED bool IsUpToDate() const override;
+ WARN_UNUSED UpToDate IsUpToDate() const override;
~EmptyAssetsProvider() override = default;
protected:
@@ -212,5 +217,3 @@ struct EmptyAssetsProvider : public AssetsProvider {
};
} // namespace android
-
-#endif /* ANDROIDFW_ASSETSPROVIDER_H */
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index d1db13f53069..0c0856315d8f 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef IDMAP_H_
-#define IDMAP_H_
+#pragma once
#include <memory>
#include <string>
@@ -32,6 +31,31 @@
namespace android {
+// An enum that tracks more states than just 'up to date' or 'not' for a resources container:
+// there are several cases where we know for sure that the object can't change and won't get
+// out of date. Reporting those states to the managed layer allows it to stop checking here
+// completely, speeding up the cache lookups by dozens of milliseconds.
+enum class UpToDate : int { False, True, Always };
+
+// Combines two UpToDate values, and only accesses the second one if it matters to the result.
+template <class Getter>
+UpToDate combine(UpToDate first, Getter secondGetter) {
+ switch (first) {
+ case UpToDate::False:
+ return UpToDate::False;
+ case UpToDate::True: {
+ const auto second = secondGetter();
+ return second == UpToDate::False ? UpToDate::False : UpToDate::True;
+ }
+ case UpToDate::Always:
+ return secondGetter();
+ }
+}
+
+inline UpToDate fromBool(bool value) {
+ return value ? UpToDate::True : UpToDate::False;
+}
+
class LoadedIdmap;
class IdmapResMap;
struct Idmap_header;
@@ -197,7 +221,7 @@ class LoadedIdmap {
// Returns whether the idmap file on disk has not been modified since the construction of this
// LoadedIdmap.
- bool IsUpToDate() const;
+ UpToDate IsUpToDate() const;
protected:
// Exposed as protected so that tests can subclass and mock this class out.
@@ -237,5 +261,3 @@ class LoadedIdmap {
};
} // namespace android
-
-#endif // IDMAP_H_
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 8b2871c21a1e..30594dcfa939 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -47,6 +47,8 @@
namespace android {
+constexpr const bool kDeviceEndiannessSame = dtohs(0x1001) == 0x1001;
+
constexpr const uint32_t kIdmapMagic = 0x504D4449u;
constexpr const uint32_t kIdmapCurrentVersion = 0x0000000Bu;
@@ -408,7 +410,16 @@ struct Res_value
typedef uint32_t data_type;
data_type data;
- void copyFrom_dtoh(const Res_value& src);
+ void copyFrom_dtoh(const Res_value& src) {
+ if constexpr (kDeviceEndiannessSame) {
+ *this = src;
+ } else {
+ copyFrom_dtoh_slow(src);
+ }
+ }
+
+ private:
+ void copyFrom_dtoh_slow(const Res_value& src);
};
/**
@@ -1254,11 +1265,32 @@ struct ResTable_config
// Varies in length from 3 to 8 chars. Zero-filled value.
char localeNumberingSystem[8];
- void copyFromDeviceNoSwap(const ResTable_config& o);
-
- void copyFromDtoH(const ResTable_config& o);
-
- void swapHtoD();
+ void copyFromDeviceNoSwap(const ResTable_config& o) {
+ const auto o_size = dtohl(o.size);
+ if (o_size >= sizeof(ResTable_config)) [[likely]] {
+ *this = o;
+ } else {
+ memcpy(this, &o, o_size);
+ memset(((uint8_t*)this) + o_size, 0, sizeof(ResTable_config) - o_size);
+ }
+ this->size = sizeof(*this);
+ }
+
+ void copyFromDtoH(const ResTable_config& o) {
+ if constexpr (kDeviceEndiannessSame) {
+ copyFromDeviceNoSwap(o);
+ } else {
+ copyFromDtoH_slow(o);
+ }
+ }
+
+ void swapHtoD() {
+ if constexpr (kDeviceEndiannessSame) {
+ ; // noop
+ } else {
+ swapHtoD_slow();
+ }
+ }
int compare(const ResTable_config& o) const;
int compareLogical(const ResTable_config& o) const;
@@ -1384,6 +1416,10 @@ struct ResTable_config
bool isBetterThanBeforeLocale(const ResTable_config& o, const ResTable_config* requested) const;
String8 toString() const;
+
+ private:
+ void copyFromDtoH_slow(const ResTable_config& o);
+ void swapHtoD_slow();
};
/**
diff --git a/libs/androidfw/include/androidfw/misc.h b/libs/androidfw/include/androidfw/misc.h
index c9ba8a01a5e9..d8ca64a174a2 100644
--- a/libs/androidfw/include/androidfw/misc.h
+++ b/libs/androidfw/include/androidfw/misc.h
@@ -15,6 +15,7 @@
*/
#pragma once
+#include <sys/stat.h>
#include <time.h>
//
@@ -64,10 +65,15 @@ ModDate getFileModDate(const char* fileName);
/* same, but also returns -1 if the file has already been deleted */
ModDate getFileModDate(int fd);
+// Extract the modification date from the stat structure.
+ModDate getModDate(const struct ::stat& st);
+
// Check if |path| or |fd| resides on a readonly filesystem.
bool isReadonlyFilesystem(const char* path);
bool isReadonlyFilesystem(int fd);
+bool isKnownWritablePath(const char* path);
+
} // namespace android
// Whoever uses getFileModDate() will need this as well
diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp
index 32f3624a3aee..26eb320805c9 100644
--- a/libs/androidfw/misc.cpp
+++ b/libs/androidfw/misc.cpp
@@ -16,10 +16,10 @@
#define LOG_TAG "misc"
-//
-// Miscellaneous utility functions.
-//
-#include <androidfw/misc.h>
+#include "androidfw/misc.h"
+
+#include <errno.h>
+#include <sys/stat.h>
#include "android-base/logging.h"
@@ -28,9 +28,7 @@
#include <sys/vfs.h>
#endif // __linux__
-#include <errno.h>
-#include <sys/stat.h>
-
+#include <array>
#include <cstdio>
#include <cstring>
#include <tuple>
@@ -40,28 +38,26 @@ namespace android {
/*
* Get a file's type.
*/
-FileType getFileType(const char* fileName)
-{
- struct stat sb;
-
- if (stat(fileName, &sb) < 0) {
- if (errno == ENOENT || errno == ENOTDIR)
- return kFileTypeNonexistent;
- else {
- PLOG(ERROR) << "getFileType(): stat(" << fileName << ") failed";
- return kFileTypeUnknown;
- }
- } else {
- if (S_ISREG(sb.st_mode))
- return kFileTypeRegular;
- else if (S_ISDIR(sb.st_mode))
- return kFileTypeDirectory;
- else if (S_ISCHR(sb.st_mode))
- return kFileTypeCharDev;
- else if (S_ISBLK(sb.st_mode))
- return kFileTypeBlockDev;
- else if (S_ISFIFO(sb.st_mode))
- return kFileTypeFifo;
+FileType getFileType(const char* fileName) {
+ struct stat sb;
+ if (stat(fileName, &sb) < 0) {
+ if (errno == ENOENT || errno == ENOTDIR)
+ return kFileTypeNonexistent;
+ else {
+ PLOG(ERROR) << "getFileType(): stat(" << fileName << ") failed";
+ return kFileTypeUnknown;
+ }
+ } else {
+ if (S_ISREG(sb.st_mode))
+ return kFileTypeRegular;
+ else if (S_ISDIR(sb.st_mode))
+ return kFileTypeDirectory;
+ else if (S_ISCHR(sb.st_mode))
+ return kFileTypeCharDev;
+ else if (S_ISBLK(sb.st_mode))
+ return kFileTypeBlockDev;
+ else if (S_ISFIFO(sb.st_mode))
+ return kFileTypeFifo;
#if defined(S_ISLNK)
else if (S_ISLNK(sb.st_mode))
return kFileTypeSymlink;
@@ -75,7 +71,7 @@ FileType getFileType(const char* fileName)
}
}
-static ModDate getModDate(const struct stat& st) {
+ModDate getModDate(const struct stat& st) {
#ifdef _WIN32
return st.st_mtime;
#elif defined(__APPLE__)
@@ -113,8 +109,14 @@ bool isReadonlyFilesystem(const char*) {
bool isReadonlyFilesystem(int) {
return false;
}
+bool isKnownWritablePath(const char*) {
+ return false;
+}
#else // __linux__
bool isReadonlyFilesystem(const char* path) {
+ if (isKnownWritablePath(path)) {
+ return false;
+ }
struct statfs sfs;
if (::statfs(path, &sfs)) {
PLOG(ERROR) << "isReadonlyFilesystem(): statfs(" << path << ") failed";
@@ -131,6 +133,13 @@ bool isReadonlyFilesystem(int fd) {
}
return (sfs.f_flags & ST_RDONLY) != 0;
}
+
+bool isKnownWritablePath(const char* path) {
+ // We know that all paths in /data/ are writable.
+ static constexpr char kRwPrefix[] = "/data/";
+ return strncmp(kRwPrefix, path, std::size(kRwPrefix) - 1) == 0;
+}
+
#endif // __linux__
} // namespace android
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index cb2e56f5f5e4..22b9e69500d9 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -218,10 +218,11 @@ TEST_F(IdmapTest, OverlayAssetsIsUpToDate) {
auto apk_assets = ApkAssets::LoadOverlay(temp_file.path);
ASSERT_NE(nullptr, apk_assets);
- ASSERT_TRUE(apk_assets->IsUpToDate());
+ ASSERT_TRUE(apk_assets->IsOverlay());
+ ASSERT_EQ(UpToDate::True, apk_assets->IsUpToDate());
unlink(temp_file.path);
- ASSERT_FALSE(apk_assets->IsUpToDate());
+ ASSERT_EQ(UpToDate::False, apk_assets->IsUpToDate());
const auto sleep_duration =
std::chrono::nanoseconds(std::max(kModDateResolutionNs, 1'000'000ull));
@@ -230,7 +231,27 @@ TEST_F(IdmapTest, OverlayAssetsIsUpToDate) {
base::WriteStringToFile("hello", temp_file.path);
std::this_thread::sleep_for(sleep_duration);
- ASSERT_FALSE(apk_assets->IsUpToDate());
+ ASSERT_EQ(UpToDate::False, apk_assets->IsUpToDate());
+}
+
+TEST(IdmapTestUpToDate, Combine) {
+ ASSERT_EQ(UpToDate::False, combine(UpToDate::False, [] {
+ ADD_FAILURE(); // Shouldn't get called at all.
+ return UpToDate::False;
+ }));
+
+ ASSERT_EQ(UpToDate::False, combine(UpToDate::True, [] { return UpToDate::False; }));
+
+ ASSERT_EQ(UpToDate::True, combine(UpToDate::True, [] { return UpToDate::True; }));
+ ASSERT_EQ(UpToDate::True, combine(UpToDate::True, [] { return UpToDate::Always; }));
+ ASSERT_EQ(UpToDate::True, combine(UpToDate::Always, [] { return UpToDate::True; }));
+
+ ASSERT_EQ(UpToDate::Always, combine(UpToDate::Always, [] { return UpToDate::Always; }));
+}
+
+TEST(IdmapTestUpToDate, FromBool) {
+ ASSERT_EQ(UpToDate::False, fromBool(false));
+ ASSERT_EQ(UpToDate::True, fromBool(true));
}
} // namespace
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
index 62fd7d358123..d3fc91b65829 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -137,6 +137,14 @@ flag {
}
flag {
+ name: "shader_color_space"
+ is_exported: true
+ namespace: "core_graphics"
+ description: "API to set the working colorspace of a Shader or ColorFilter"
+ bug: "299670828"
+}
+
+flag {
name: "query_global_priority"
namespace: "core_graphics"
description: "Attempt to query whether the vulkan driver supports the requested global priority before queue creation."
@@ -174,7 +182,7 @@ flag {
flag {
name: "early_preload_gl_context"
namespace: "core_graphics"
- description: "Initialize GL context and GraphicBufferAllocater init on renderThread preload. This improves app startup time for apps using GL."
+ description: "Preload GL context on renderThread preload. This improves app startup time for apps using GL."
bug: "383612849"
}
@@ -187,4 +195,12 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "early_preinit_buffer_allocator"
+ namespace: "core_graphics"
+ description: "Initialize GraphicBufferAllocater on ViewRootImpl init, to avoid blocking on init during buffer allocation, improving app launch latency."
+ bug: "389908734"
+ is_fixed_read_only: true
} \ No newline at end of file
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index eadb9dea566f..45f0fe0288a4 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -266,11 +266,17 @@ static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
}
-static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
+static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr,
+ jlong colorSpacePtr) {
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
sk_sp<SkShader> shader = builder->makeShader(matrix);
ThrowIAE_IfNull(env, shader);
+ if (colorSpace) {
+ shader = shader->makeWithWorkingColorSpace(colorSpace);
+ ThrowIAE_IfNull(env, shader);
+ }
return reinterpret_cast<jlong>(shader.release());
}
@@ -350,6 +356,10 @@ static void RuntimeShader_updateChild(JNIEnv* env, jobject, jlong shaderBuilder,
UpdateChild(env, builder, name.c_str(), childEffect);
}
+static void RuntimeShader_no(JNIEnv* env) {
+ jniThrowRuntimeException(env, "Not supported");
+}
+
///////////////////////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gShaderMethods[] = {
@@ -379,7 +389,8 @@ static const JNINativeMethod gComposeShaderMethods[] = {
static const JNINativeMethod gRuntimeShaderMethods[] = {
{"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
- {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
+ {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_no},
+ {"nativeCreateShader", "(JJJ)J", (void*)RuntimeShader_create},
{"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
{"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
(void*)RuntimeShader_updateFloatArrayUniforms},
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index df9f83036709..99e7740d66d2 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -52,6 +52,9 @@
#include <renderthread/RenderThread.h>
#include <src/image/SkImage_Base.h>
#include <thread/CommonPool.h>
+#ifdef __ANDROID__
+#include <ui/GraphicBufferAllocator.h>
+#endif
#include <utils/Color.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
@@ -849,6 +852,17 @@ static void android_view_ThreadedRenderer_preload(JNIEnv*, jclass) {
RenderProxy::preload();
}
+static void android_view_ThreadedRenderer_preInitBufferAllocator(JNIEnv*, jclass) {
+#ifdef __ANDROID__
+ CommonPool::async([] {
+ ATRACE_NAME("preInitBufferAllocator:GraphicBufferAllocator");
+ // This involves several binder calls which we do not want blocking
+ // critical path of the activity that is launching.
+ GraphicBufferAllocator::getInstance();
+ });
+#endif
+}
+
static void android_view_ThreadedRenderer_setRtAnimationsEnabled(JNIEnv* env, jobject clazz,
jboolean enabled) {
RenderProxy::setRtAnimationsEnabled(enabled);
@@ -1040,6 +1054,8 @@ static const JNINativeMethod gMethods[] = {
(void*)android_view_ThreadedRenderer_setDisplayDensityDpi},
{"nInitDisplayInfo", "(IIFIJJZZZ)V", (void*)android_view_ThreadedRenderer_initDisplayInfo},
{"preload", "()V", (void*)android_view_ThreadedRenderer_preload},
+ {"preInitBufferAllocator", "()V",
+ (void*)android_view_ThreadedRenderer_preInitBufferAllocator},
{"isWebViewOverlaysEnabled", "()Z",
(void*)android_view_ThreadedRenderer_isWebViewOverlaysEnabled},
{"nSetDrawingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDrawingEnabled},
diff --git a/location/Android.bp b/location/Android.bp
index bc02d1f852de..80556a2376bf 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -42,6 +42,7 @@ java_sdk_library {
"FlaggedApi",
],
},
+ jarjar_prefix: "com.android.internal.hidden_from_bootclasspath",
}
platform_compat_config {
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
index e1fbfea19235..892a8612d74a 100644
--- a/media/java/android/media/AudioDeviceVolumeManager.java
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -86,10 +86,10 @@ public class AudioDeviceVolumeManager {
/**
* @hide
* Interface to receive volume changes on a device that behaves in absolute volume mode.
- * @see #setDeviceAbsoluteMultiVolumeBehavior(AudioDeviceAttributes, List, Executor,
- * OnAudioDeviceVolumeChangeListener)
- * @see #setDeviceAbsoluteVolumeBehavior(AudioDeviceAttributes, VolumeInfo, Executor,
- * OnAudioDeviceVolumeChangeListener)
+ * @see #setDeviceAbsoluteMultiVolumeBehavior(AudioDeviceAttributes, List, boolean, Executor,
+ * OnAudioDeviceVolumeChangedListener)
+ * @see #setDeviceAbsoluteVolumeBehavior(AudioDeviceAttributes, VolumeInfo, boolean, Executor,
+ * OnAudioDeviceVolumeChangedListener)
*/
public interface OnAudioDeviceVolumeChangedListener {
/**
@@ -203,6 +203,9 @@ public class AudioDeviceVolumeManager {
* volume updates to apply on that device
* @param device the audio device set to absolute volume mode
* @param volume the type of volume this device responds to
+ * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately
+ * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume}
+ * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}.
* @param executor the Executor used for receiving volume updates through the listener
* @param vclistener the callback for volume updates
*/
@@ -211,13 +214,13 @@ public class AudioDeviceVolumeManager {
public void setDeviceAbsoluteVolumeBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull VolumeInfo volume,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment) {
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
final ArrayList<VolumeInfo> volumes = new ArrayList<>(1);
volumes.add(volume);
- setDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener,
- handlesVolumeAdjustment);
+ setDeviceAbsoluteMultiVolumeBehavior(device, volumes, handlesVolumeAdjustment, executor,
+ vclistener);
}
/**
@@ -226,20 +229,20 @@ public class AudioDeviceVolumeManager {
* registers a listener for receiving volume updates to apply on that device
* @param device the audio device set to absolute multi-volume mode
* @param volumes the list of volumes the given device responds to
+ * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately
+ * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume}
+ * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}.
* @param executor the Executor used for receiving volume updates through the listener
* @param vclistener the callback for volume updates
- * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately
- * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume}
- * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}.
*/
@RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
android.Manifest.permission.BLUETOOTH_PRIVILEGED })
public void setDeviceAbsoluteMultiVolumeBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull List<VolumeInfo> volumes,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment) {
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
baseSetDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener,
handlesVolumeAdjustment, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
}
@@ -249,11 +252,14 @@ public class AudioDeviceVolumeManager {
* Configures a device to use absolute volume model, and registers a listener for receiving
* volume updates to apply on that device.
*
- * Should be used instead of {@link #setDeviceAbsoluteVolumeBehavior} when there is no reliable
- * way to set the device's volume to a percentage.
+ * <p>Should be used instead of {@link #setDeviceAbsoluteVolumeBehavior} when there is no
+ * reliable way to set the device's volume to a percentage.
*
* @param device the audio device set to absolute volume mode
* @param volume the type of volume this device responds to
+ * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately
+ * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume}
+ * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}.
* @param executor the Executor used for receiving volume updates through the listener
* @param vclistener the callback for volume updates
*/
@@ -262,13 +268,13 @@ public class AudioDeviceVolumeManager {
public void setDeviceAbsoluteVolumeAdjustOnlyBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull VolumeInfo volume,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment) {
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
final ArrayList<VolumeInfo> volumes = new ArrayList<>(1);
volumes.add(volume);
- setDeviceAbsoluteMultiVolumeAdjustOnlyBehavior(device, volumes, executor, vclistener,
- handlesVolumeAdjustment);
+ setDeviceAbsoluteMultiVolumeAdjustOnlyBehavior(device, volumes, handlesVolumeAdjustment,
+ executor, vclistener);
}
/**
@@ -276,11 +282,14 @@ public class AudioDeviceVolumeManager {
* Configures a device to use absolute volume model applied to different volume types, and
* registers a listener for receiving volume updates to apply on that device.
*
- * Should be used instead of {@link #setDeviceAbsoluteMultiVolumeBehavior} when there is
+ * <p>Should be used instead of {@link #setDeviceAbsoluteMultiVolumeBehavior} when there is
* no reliable way to set the device's volume to a percentage.
*
* @param device the audio device set to absolute multi-volume mode
* @param volumes the list of volumes the given device responds to
+ * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately
+ * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume}
+ * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}.
* @param executor the Executor used for receiving volume updates through the listener
* @param vclistener the callback for volume updates
*/
@@ -289,16 +298,16 @@ public class AudioDeviceVolumeManager {
public void setDeviceAbsoluteMultiVolumeAdjustOnlyBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull List<VolumeInfo> volumes,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment) {
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
baseSetDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener,
handlesVolumeAdjustment, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
}
/**
* Base method for configuring a device to use absolute volume behavior, or one of its variants.
- * See {@link AudioManager#AbsoluteDeviceVolumeBehavior} for a list of allowed behaviors.
+ * See {@link AudioManager.AbsoluteDeviceVolumeBehavior} for a list of allowed behaviors.
*
* @param behavior the variant of absolute device volume behavior to adopt
*/
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 12d7f33a0d51..e01cb928e369 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1754,13 +1754,21 @@ public class AudioSystem
@UnsupportedAppUsage
public static int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
int codecFormat) {
+ return setDeviceConnectionState(attributes, state, codecFormat, false /*deviceSwitch*/);
+ }
+
+ /**
+ * @hide
+ */
+ public static int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+ int codecFormat, boolean deviceSwitch) {
android.media.audio.common.AudioPort port =
AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes);
Parcel parcel = Parcel.obtain();
port.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
try {
- return setDeviceConnectionState(state, parcel, codecFormat);
+ return setDeviceConnectionState(state, parcel, codecFormat, deviceSwitch);
} finally {
parcel.recycle();
}
@@ -1769,7 +1777,10 @@ public class AudioSystem
* @hide
*/
@UnsupportedAppUsage
- public static native int setDeviceConnectionState(int state, Parcel parcel, int codecFormat);
+ public static native int setDeviceConnectionState(int state, Parcel parcel, int codecFormat,
+ boolean deviceSwitch);
+
+
/** @hide */
@UnsupportedAppUsage
public static native int getDeviceConnectionState(int device, String device_address);
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index fb1b5b57cce6..15c832392a22 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -4060,6 +4060,7 @@ final public class MediaCodec {
* Finish building a queue request and queue the buffers with tunings.
*/
public void queue() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIDEO, "MediaCodec::queueRequest-queue#java");
if (!isAccessible()) {
throw new IllegalStateException("The request is stale");
}
@@ -4088,6 +4089,7 @@ final public class MediaCodec {
mTuningKeys, mTuningValues);
}
clear();
+ Trace.traceEnd(Trace.TRACE_TAG_VIDEO);
}
@NonNull QueueRequest clear() {
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 3104f9d42891..e94fb7d9e52b 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -55,6 +55,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -96,12 +97,10 @@ public abstract class MediaRoute2ProviderService extends Service {
* system media, as described by {@link MediaRoute2Info#getSupportedRoutingTypes()}.
*
* @see #onCreateSystemRoutingSession
- * @hide
*/
- // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
@FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
@SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY)
- public static final String SERVICE_INTERFACE_SYSTEM_MEDIA =
+ public static final String CATEGORY_SYSTEM_MEDIA =
"android.media.MediaRoute2ProviderService.SYSTEM_MEDIA";
/**
@@ -165,9 +164,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* The request has failed because the requested operation is not implemented by the provider.
*
* @see #notifyRequestFailed
- * @hide
*/
- // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
@FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
public static final int REASON_UNIMPLEMENTED = 5;
@@ -175,9 +172,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* The request has failed because the provider has failed to route system media.
*
* @see #notifyRequestFailed
- * @hide
*/
- // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
@FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
public static final int REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA = 6;
@@ -217,7 +212,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* package (for example, if they affect the entire system).
*/
@GuardedBy("mRequestIdsLock")
- private final LongSparseArray<Integer> mSystemMediaSessionCreationRequests =
+ private final LongSparseArray<Integer> mSystemRoutingSessionCreationRequests =
new LongSparseArray<>();
@GuardedBy("mSessionLock")
@@ -350,7 +345,7 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Notifies the system of the successful creation of a system media routing session.
*
- * <p>This method can only be called as the result of a prior call to {@link
+ * <p>This method must only be called as the result of a prior call to {@link
* #onCreateSystemRoutingSession}.
*
* @param requestId the ID of the {@link #onCreateSystemRoutingSession} request which this call
@@ -365,13 +360,13 @@ public abstract class MediaRoute2ProviderService extends Service {
* where you can clean up this session. {@link AudioRecord#startRecording()} must be called
* immediately on {@link MediaStreams#getAudioRecord()} after calling this method, in order
* to start streaming audio to the receiver.
- * @hide
+ * @throws IllegalStateException If the provided {@code requestId} doesn't correspond to a
+ * previous call to {@link #onCreateSystemRoutingSession}.
*/
- // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
@FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
@RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
@Nullable
- public final MediaStreams notifySystemMediaSessionCreated(
+ public final MediaStreams notifySystemRoutingSessionCreated(
long requestId,
@NonNull RoutingSessionInfo sessionInfo,
@NonNull MediaStreamsFormats formats) {
@@ -380,7 +375,7 @@ public abstract class MediaRoute2ProviderService extends Service {
if (DEBUG) {
Log.d(
TAG,
- "notifySystemMediaSessionCreated: Creating a session. requestId="
+ "notifySystemRoutingSessionCreated: Creating a session. requestId="
+ requestId
+ ", sessionInfo="
+ sessionInfo);
@@ -388,8 +383,8 @@ public abstract class MediaRoute2ProviderService extends Service {
Integer uid;
synchronized (mRequestIdsLock) {
- uid = mSystemMediaSessionCreationRequests.get(requestId);
- mSystemMediaSessionCreationRequests.remove(requestId);
+ uid = mSystemRoutingSessionCreationRequests.get(requestId);
+ mSystemRoutingSessionCreationRequests.remove(requestId);
}
if (uid == null) {
@@ -656,37 +651,34 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Called when the service receives a request to create a system routing session.
*
- * <p>This method will only be called for routes that support routing of the system media, as
- * described by {@link MediaRoute2Info#getSupportedRoutingTypes()}.
+ * <p>This method must be overridden by subclasses that support routes that support routing
+ * {@link MediaRoute2Info#getSupportedRoutingTypes() system media}. The provided {@code routeId}
+ * will always correspond to a route that supports routing of the system media, as per {@link
+ * MediaRoute2Info#getSupportedRoutingTypes()}.
*
- * <p>Implementors of this method must call {@link #notifySystemMediaSessionCreated} with the
+ * <p>Implementors of this method must call {@link #notifySystemRoutingSessionCreated} with the
* given {@code requestId} to indicate a successful session creation. If the session creation
* fails (for example, if the connection to the receiver device fails), the implementor must
* call {@link #notifyRequestFailed}, passing the {@code requestId}.
*
* <p>Unlike {@link #onCreateSession}, system sessions route the system media (for example,
* audio and/or video) which is to be retrieved by calling {@link
- * #notifySystemMediaSessionCreated}.
+ * #notifySystemRoutingSessionCreated}.
*
* <p>Changes to the session can be notified by calling {@link #notifySessionUpdated}.
*
* @param requestId the ID of this request
- * @param packageName the package name of the application whose media to route.
* @param routeId the ID of the route initially being {@link
* RoutingSessionInfo#getSelectedRoutes() selected}.
- * @param sessionHints an optional bundle of arguments sent by {@link MediaRouter2}, or null if
- * none.
+ * @param parameters {@link SystemRoutingSessionParams} for the session creation.
* @see RoutingSessionInfo.Builder
- * @see #notifySystemMediaSessionCreated
- * @hide
+ * @see #notifySystemRoutingSessionCreated
*/
- // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
@FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
public void onCreateSystemRoutingSession(
long requestId,
- @NonNull String packageName,
@NonNull String routeId,
- @Nullable Bundle sessionHints) {
+ @NonNull SystemRoutingSessionParams parameters) {
mHandler.post(() -> notifyRequestFailed(requestId, REASON_UNIMPLEMENTED));
}
@@ -974,24 +966,29 @@ public abstract class MediaRoute2ProviderService extends Service {
int uid,
String packageName,
String routeId,
- @Nullable Bundle sessionHints) {
- if (!checkCallerIsSystem()) {
+ @Nullable Bundle extras) {
+ if (!Flags.enableMirroringInMediaRouter2() || !checkCallerIsSystem()) {
return;
}
if (!checkRouteIdIsValid(routeId, "requestCreateSession")) {
return;
}
synchronized (mRequestIdsLock) {
- mSystemMediaSessionCreationRequests.put(requestId, uid);
+ mSystemRoutingSessionCreationRequests.put(requestId, uid);
}
+ var sessionParamsBuilder =
+ new SystemRoutingSessionParams.Builder().setPackageName(packageName);
+ if (extras != null) {
+ sessionParamsBuilder.setExtras(extras);
+ }
+ var sessionParams = sessionParamsBuilder.build();
mHandler.sendMessage(
obtainMessage(
MediaRoute2ProviderService::onCreateSystemRoutingSession,
MediaRoute2ProviderService.this,
requestId,
- packageName,
routeId,
- sessionHints));
+ sessionParams));
}
@Override
@@ -1072,14 +1069,12 @@ public abstract class MediaRoute2ProviderService extends Service {
}
/**
- * Holds the streams to be routed as part of a system media routing session.
- *
- * <p>The encoded data format matches the {@link MediaStreamsFormats} passed to {@link
- * #notifySystemMediaSessionCreated}.
+ * Holds the streams to be routed as part of a {@link #onCreateSystemRoutingSession system media
+ * routing session}.
*
- * @hide
+ * <p>The encoded data format will match the {@link MediaStreamsFormats} passed to {@link
+ * #notifySystemRoutingSessionCreated}.
*/
- // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
@FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
public static final class MediaStreams {
@@ -1088,8 +1083,6 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Holds the last {@link RoutingSessionInfo} associated with these streams.
- *
- * @hide
*/
@NonNull
// Access guarded by mSessionsLock, but it's not convenient to enforce through @GuardedBy.
@@ -1147,15 +1140,91 @@ public abstract class MediaRoute2ProviderService extends Service {
}
}
+ /**
+ * Holds parameters associated with a {@link #onCreateSystemRoutingSession session creation
+ * request}.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
+ public static final class SystemRoutingSessionParams {
+
+ private final String mPackageName;
+ private final Bundle mExtras;
+
+ private SystemRoutingSessionParams(Builder builder) {
+ this.mPackageName = builder.mPackageName;
+ this.mExtras = builder.mExtras;
+ }
+
+ /**
+ * Returns the name of the package associated with the session, or an empty string if not
+ * applicable.
+ *
+ * <p>The package name is not applicable if the session is not associated with a specific
+ * package, for example is the session affects the entire system.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /** Returns a bundle provided by the client that triggered the session creation request. */
+ @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
+ @NonNull
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ /** A builder for {@link SystemRoutingSessionParams}. */
+ public static final class Builder {
+ private String mPackageName;
+ private Bundle mExtras;
+
+ /** Constructor. */
+ public Builder() {
+ mPackageName = "";
+ mExtras = Bundle.EMPTY;
+ }
+
+ /**
+ * Sets the {@link #getExtras() extras}.
+ *
+ * <p>The default value is an empty {@link Bundle}.
+ *
+ * <p>Note that this bundle is not copied, so avoiding mutating the given {@link Bundle}
+ * after passing it to this method.
+ */
+ @NonNull
+ public Builder setExtras(@NonNull Bundle extras) {
+ mExtras = Objects.requireNonNull(extras);
+ return this;
+ }
+
+ /**
+ * Sets the {@link #getPackageName()}.
+ *
+ * <p>The default value is an empty string.
+ */
+ @NonNull
+ public Builder setPackageName(@NonNull String packageName) {
+ mPackageName = Objects.requireNonNull(packageName);
+ return this;
+ }
+
+ /** Returns a new {@link SystemRoutingSessionParams} instance. */
+ @NonNull
+ public SystemRoutingSessionParams build() {
+ return new SystemRoutingSessionParams(this);
+ }
+ }
+ }
/**
* Holds the formats to encode media data to be read from {@link MediaStreams}.
*
* @see MediaStreams
- * @see #notifySystemMediaSessionCreated
- * @hide
+ * @see #notifySystemRoutingSessionCreated
*/
- // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
@FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
public static final class MediaStreamsFormats {
@@ -1169,29 +1238,25 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Returns the audio format to use for creating the {@link MediaStreams#getAudioRecord} to
- * return from {@link #notifySystemMediaSessionCreated}.
- *
- * @hide
+ * return from {@link #notifySystemRoutingSessionCreated}. May be null if the session
+ * doesn't support system audio.
*/
- // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
@FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
+ @Nullable
public AudioFormat getAudioFormat() {
return mAudioFormat;
}
/**
* Builder for {@link MediaStreamsFormats}
- *
- * @hide
*/
- // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
@FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
public static final class Builder {
private AudioFormat mAudioFormat;
/**
* Sets the audio format to use for creating the {@link MediaStreams#getAudioRecord} to
- * return from {@link #notifySystemMediaSessionCreated}.
+ * return from {@link #notifySystemRoutingSessionCreated}.
*
* @param audioFormat the audio format
* @return this builder
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 0f24654879cd..021348153bb8 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -60,6 +60,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* RingtoneManager provides access to ringtones, notification, and other types
@@ -810,9 +811,7 @@ public class RingtoneManager {
// Don't set the stream type
Ringtone ringtone = getRingtone(context, ringtoneUri, -1 /* streamType */,
volumeShaperConfig, false);
- if (Flags.enableRingtoneHapticsCustomization()
- && Utils.isRingtoneVibrationSettingsSupported(context)
- && Utils.hasVibration(ringtoneUri) && hasHapticChannels(ringtoneUri)) {
+ if (muteHapticChannelForVibration(context, ringtoneUri)) {
audioAttributes = new AudioAttributes.Builder(
audioAttributes).setHapticChannelsMuted(true).build();
}
@@ -1305,4 +1304,19 @@ public class RingtoneManager {
default: throw new IllegalArgumentException();
}
}
+
+ private static boolean muteHapticChannelForVibration(Context context, Uri ringtoneUri) {
+ final Uri vibrationUri = Utils.getVibrationUri(ringtoneUri);
+ // No vibration is specified
+ if (vibrationUri == null) {
+ return false;
+ }
+ // The user specified the synchronized pattern
+ if (Objects.equals(vibrationUri.toString(), Utils.SYNCHRONIZED_VIBRATION)) {
+ return false;
+ }
+ return Flags.enableRingtoneHapticsCustomization()
+ && Utils.isRingtoneVibrationSettingsSupported(context)
+ && hasHapticChannels(ringtoneUri);
+ }
}
diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java
index 11bd221ec696..d6e27b0ffa75 100644
--- a/media/java/android/media/Utils.java
+++ b/media/java/android/media/Utils.java
@@ -66,6 +66,8 @@ public class Utils {
public static final String VIBRATION_URI_PARAM = "vibration_uri";
+ public static final String SYNCHRONIZED_VIBRATION = "synchronized";
+
/**
* Sorts distinct (non-intersecting) range array in ascending order.
* @throws java.lang.IllegalArgumentException if ranges are not distinct
@@ -757,8 +759,8 @@ public class Utils {
return null;
}
String filePath = vibrationUri.getPath();
- if (filePath == null) {
- Log.w(TAG, "The file path is null.");
+ if (filePath == null || filePath.equals(Utils.SYNCHRONIZED_VIBRATION)) {
+ Log.w(TAG, "Ignore the vibration parsing for file:" + filePath);
return null;
}
File vibrationFile = new File(filePath);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index f09dc7218d7d..6b7217358b6e 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -25,8 +25,6 @@ cc_library_shared {
min_sdk_version: "",
srcs: [
- "android_media_ImageWriter.cpp",
- "android_media_ImageReader.cpp",
"android_media_JetPlayer.cpp",
"android_media_MediaCrypto.cpp",
"android_media_MediaCodec.cpp",
@@ -42,7 +40,6 @@ cc_library_shared {
"android_media_MediaProfiles.cpp",
"android_media_MediaRecorder.cpp",
"android_media_MediaSync.cpp",
- "android_media_PublicFormatUtils.cpp",
"android_media_ResampleInputStream.cpp",
"android_media_Streams.cpp",
"android_media_SyncParams.cpp",
@@ -64,7 +61,6 @@ cc_library_shared {
"libbinder",
"libmedia",
"libmedia_codeclist",
- "libmedia_jni_utils",
"libmedia_omx",
"libmediametrics",
"libmediadrm",
@@ -133,38 +129,6 @@ cc_library_shared {
}
cc_library_shared {
- name: "libmedia_jni_utils",
- srcs: [
- ":libgui_frame_event_aidl",
- "android_media_Utils.cpp",
- ],
-
- header_libs: [
- "libgui_headers",
- ],
-
- shared_libs: [
- "liblog",
- "libui",
- "libutils",
- ],
-
- include_dirs: [
- "system/media/camera/include",
- ],
-
- export_include_dirs: ["."],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wunused",
- "-Wunreachable-code",
- ],
-}
-
-cc_library_shared {
name: "libmedia_tv_tuner",
min_sdk_version: "",
srcs: [
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index a94230014437..9d197f48ed8d 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1378,7 +1378,7 @@ static jintArray android_media_MediaPlayer_getRoutedDeviceIds(JNIEnv *env, jobje
}
jint* values = env->GetIntArrayElements(result, 0);
for (unsigned int i = 0; i < deviceIds.size(); i++) {
- values[i++] = static_cast<jint>(deviceIds[i]);
+ values[i] = static_cast<jint>(deviceIds[i]);
}
env->ReleaseIntArrayElements(result, values, 0);
return result;
@@ -1476,8 +1476,6 @@ static int register_android_media_MediaPlayer(JNIEnv *env)
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaPlayer", gMethods, NELEM(gMethods));
}
-extern int register_android_media_ImageReader(JNIEnv *env);
-extern int register_android_media_ImageWriter(JNIEnv *env);
extern int register_android_media_JetPlayer(JNIEnv *env);
extern int register_android_media_Crypto(JNIEnv *env);
extern int register_android_media_Drm(JNIEnv *env);
@@ -1490,7 +1488,6 @@ extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
extern int register_android_media_MediaMuxer(JNIEnv *env);
extern int register_android_media_MediaRecorder(JNIEnv *env);
extern int register_android_media_MediaSync(JNIEnv *env);
-extern int register_android_media_PublicFormatUtils(JNIEnv *env);
extern int register_android_media_ResampleInputStream(JNIEnv *env);
extern int register_android_media_MediaProfiles(JNIEnv *env);
extern int register_android_mtp_MtpDatabase(JNIEnv *env);
@@ -1508,16 +1505,6 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
}
assert(env != NULL);
- if (register_android_media_ImageWriter(env) != JNI_OK) {
- ALOGE("ERROR: ImageWriter native registration failed");
- goto bail;
- }
-
- if (register_android_media_ImageReader(env) < 0) {
- ALOGE("ERROR: ImageReader native registration failed");
- goto bail;
- }
-
if (register_android_media_JetPlayer(env) < 0) {
ALOGE("ERROR: JetPlayer native registration failed");
goto bail;
@@ -1538,11 +1525,6 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
goto bail;
}
- if (register_android_media_PublicFormatUtils(env) < 0) {
- ALOGE("ERROR: PublicFormatUtils native registration failed\n");
- goto bail;
- }
-
if (register_android_media_ResampleInputStream(env) < 0) {
ALOGE("ERROR: ResampleInputStream native registration failed\n");
goto bail;
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 643fc8a2d925..2975a39c5fa5 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -743,7 +743,7 @@ android_media_MediaRecorder_getRoutedDeviceIds(JNIEnv *env, jobject thiz)
}
jint* values = env->GetIntArrayElements(result, 0);
for (unsigned int i = 0; i < deviceIds.size(); i++) {
- values[i++] = static_cast<jint>(deviceIds[i]);
+ values[i] = static_cast<jint>(deviceIds[i]);
}
env->ReleaseIntArrayElements(result, values, 0);
return result;
diff --git a/nfc-extras/OWNERS b/nfc-extras/OWNERS
index 35e9713f5715..2b82bc8ad073 100644
--- a/nfc-extras/OWNERS
+++ b/nfc-extras/OWNERS
@@ -1,2 +1,2 @@
# Bug component: 48448
-include platform/packages/apps/Nfc:/OWNERS
+include platform/packages/modules/Nfc:/OWNERS
diff --git a/nfc-non-updatable/OWNERS b/nfc-non-updatable/OWNERS
index f46dccd97974..47f209ffa9fa 100644
--- a/nfc-non-updatable/OWNERS
+++ b/nfc-non-updatable/OWNERS
@@ -1,2 +1,2 @@
# Bug component: 48448
-include platform/packages/apps/Nfc:/OWNERS \ No newline at end of file
+include platform/packages/modules/Nfc:/OWNERS \ No newline at end of file
diff --git a/nfc-non-updatable/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc-non-updatable/java/android/nfc/cardemulation/ApduServiceInfo.java
index d0de1fc14b0e..f2a68afbfcbe 100644
--- a/nfc-non-updatable/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc-non-updatable/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -70,6 +70,11 @@ import java.util.regex.Pattern;
public final class ApduServiceInfo implements Parcelable {
private static final String TAG = "ApduServiceInfo";
+ private static final Pattern PLPF_PATTERN =
+ Pattern.compile("[0-9A-Fa-f]{2,}[0-9A-Fa-f,\\?,\\*\\.]*");
+ private static final Pattern PLF_PATTERN =
+ Pattern.compile("[0-9A-Fa-f]{2,}");
+
/**
* Component level {@link android.content.pm.PackageManager.Property PackageManager
* .Property} for a system application to change its icon and label
@@ -472,7 +477,12 @@ public final class ApduServiceInfo implements Parcelable {
boolean autoTransact = a.getBoolean(
com.android.internal.R.styleable.PollingLoopFilter_autoTransact,
false);
- if (!mOnHost && !autoTransact) {
+ boolean isValidFilter = PLF_PATTERN.matcher(plf).matches()
+ && plf.length() % 2 == 0;
+ if (!isValidFilter) {
+ Log.e(TAG, "Ignoring polling-loop-filter " + plf
+ + " it is not a valid filter");
+ } else if (!mOnHost && !autoTransact) {
Log.e(TAG, "Ignoring polling-loop-filter " + plf
+ " for offhost service that isn't autoTransact");
} else {
@@ -489,8 +499,12 @@ public final class ApduServiceInfo implements Parcelable {
boolean autoTransact = a.getBoolean(
com.android.internal.R.styleable.PollingLoopFilter_autoTransact,
false);
- if (!mOnHost && !autoTransact) {
- Log.e(TAG, "Ignoring polling-loop-filter " + plf
+ boolean isValidFilter = PLPF_PATTERN.matcher(plf).matches();
+ if (!isValidFilter) {
+ Log.e(TAG, "Ignoring polling-loop-pattern-filter " + plf
+ + " it is not a valid pattern filter");
+ } else if (!mOnHost && !autoTransact) {
+ Log.e(TAG, "Ignoring polling-loop-pattern-filter " + plf
+ " for offhost service that isn't autoTransact");
} else {
mAutoTransactPatterns.put(Pattern.compile(plf), autoTransact);
@@ -814,6 +828,12 @@ public final class ApduServiceInfo implements Parcelable {
@FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
public void addPollingLoopFilter(@NonNull String pollingLoopFilter,
boolean autoTransact) {
+ if (!PLF_PATTERN.matcher(pollingLoopFilter).matches()
+ || pollingLoopFilter.length() % 2 != 0) {
+ throw new IllegalArgumentException(
+ "Polling loop filter must contain an even number of characters 0-9 or A-F"
+ );
+ }
if (!mOnHost && !autoTransact) {
return;
}
@@ -842,6 +862,11 @@ public final class ApduServiceInfo implements Parcelable {
@FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
public void addPollingLoopPatternFilter(@NonNull String pollingLoopPatternFilter,
boolean autoTransact) {
+ if (!PLPF_PATTERN.matcher(pollingLoopPatternFilter).matches()) {
+ throw new IllegalArgumentException(
+ "Polling loop pattern filter is invalid"
+ );
+ }
if (!mOnHost && !autoTransact) {
return;
}
diff --git a/omapi/OWNERS b/omapi/OWNERS
index 39c5c5bdeb09..375d643f7ed1 100644
--- a/omapi/OWNERS
+++ b/omapi/OWNERS
@@ -1,2 +1,2 @@
# Bug component: 456592
-include platform/packages/apps/Nfc:/OWNERS
+include platform/packages/modules/Nfc:/OWNERS
diff --git a/omapi/java/android/se/OWNERS b/omapi/java/android/se/OWNERS
index 39c5c5bdeb09..375d643f7ed1 100644
--- a/omapi/java/android/se/OWNERS
+++ b/omapi/java/android/se/OWNERS
@@ -1,2 +1,2 @@
# Bug component: 456592
-include platform/packages/apps/Nfc:/OWNERS
+include platform/packages/modules/Nfc:/OWNERS
diff --git a/omapi/java/android/se/omapi/OWNERS b/omapi/java/android/se/omapi/OWNERS
index 39c5c5bdeb09..375d643f7ed1 100644
--- a/omapi/java/android/se/omapi/OWNERS
+++ b/omapi/java/android/se/omapi/OWNERS
@@ -1,2 +1,2 @@
# Bug component: 456592
-include platform/packages/apps/Nfc:/OWNERS
+include platform/packages/modules/Nfc:/OWNERS
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index efbc6d92981a..5b6ea65e42ed 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"تطبيق \"مدير الجهاز المصاحب\""</string>
<string name="confirmation_title" msgid="2244241995958340998">"‏هل تريد السماح لـ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;؟"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"يُرجى التأكّد من أنّ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> مفعَّل في <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>، وجعل <xliff:g id="PROFILE_NAME">%3$s</xliff:g> بالقرب منك."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"يُرجى التأكّد من تفعيل <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> في <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>، وإبقاء <xliff:g id="PROFILE_NAME">%3$s</xliff:g> بالقرب منك."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"لم يتم العثور على أي أجهزة. يُرجى إعادة المحاولة لاحقًا."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"البلوتوث"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
@@ -63,7 +63,7 @@
<string name="permission_microphone" msgid="2152206421428732949">"الميكروفون"</string>
<string name="permission_call_logs" msgid="5546761417694586041">"سجلّ المكالمات"</string>
<string name="permission_nearby_devices" msgid="7530973297737123481">"الأجهزة المجاورة"</string>
- <string name="permission_media_routing_control" msgid="5498639511586715253">"تغيير جهاز إخراج الوسائط"</string>
+ <string name="permission_media_routing_control" msgid="5498639511586715253">"تغيير جهاز بث الوسائط"</string>
<string name="permission_storage" msgid="6831099350839392343">"الصور والوسائط"</string>
<string name="permission_notifications" msgid="4099418516590632909">"الإشعارات"</string>
<string name="permission_phone_summary" msgid="8246321093970051702">"إجراء المكالمات الهاتفية وإدارتها"</string>
@@ -77,7 +77,7 @@
<string name="permission_notifications_summary" msgid="2272810466047367030">"‏• قراءة كل الإشعارات بما فيها المعلومات، مثل جهات الاتصال والرسائل والصور&lt;br/&gt;• إرسال الإشعارات&lt;br/&gt;&lt;br/&gt;يمكنك إدارة الإذن الممنوح لهذا التطبيق بقراءة الإشعارات وإرسالها في أي وقت من خلال الإعدادات &gt; الإشعارات."</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="permission_media_routing_control_summary" msgid="2714631092321412250">"يتيح لك هذا الإذن الاطّلاع على مجموعة من الأجهزة المتاحة وتحديد الجهاز المسموح له بتشغيل الصوت أو الفيديو أو بثّهما من التطبيقات الأخرى."</string>
- <string name="device_type" product="default" msgid="8268703872070046263">"هاتف"</string>
+ <string name="device_type" product="default" msgid="8268703872070046263">"الهاتف"</string>
<string name="device_type" product="tablet" msgid="5038791954983067774">"جهاز لوحي"</string>
<string name="device_type" product="tv" msgid="5355611506659405636">"تلفزيون"</string>
<string name="device_type" product="device" msgid="1526125965802507189">"جهاز"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index ab52c39b34b9..dfe3cbefcb5b 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -18,16 +18,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menadžer pridruženog uređaja"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Dozvolite da aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Uverite se da je za <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> uključen <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> i da u blizini imate <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Uverite se da je na <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> uključen <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> i da u blizini imate <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nije pronađen nijedan uređaj. Probajte ponovo kasnije."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"WiFi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth i WiFi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> koji želite da podesite"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> koji želite da podesite"</string>
<string name="single_device_title" msgid="4199861437545438606">"Traži se <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="8134580124808507407">"Ovoj aplikaciji će biti dozvoljeno da sinhronizuje podatke, poput imena pozivaoca, i pristupa tim dozvolama na uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"Ovoj aplikaciji će biti dozvoljeno da sinhronizuje podatke, poput imena pozivaoca, i pristupa sledećim dozvolama na <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite li da dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>
<string name="summary_glasses" msgid="5469208629679579157">"Ovoj aplikaciji će biti dozvoljeno da pristupa ovim dozvolama na uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 884101fe718d..6e5e1b58f362 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -18,15 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менеджар спадарожнай прылады"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ да прылады &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Упэўніцеся, што на гэтай прыладзе (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) уключаны <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, і трымайце <xliff:g id="PROFILE_NAME">%3$s</xliff:g> паблізу."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Упэўніцеся, што на гэтай прыладзе (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) уключаны <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, а <xliff:g id="PROFILE_NAME">%3$s</xliff:g> знаходзіцца паблізу."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Прылады не знойдзены. Паўтарыце спробу пазней."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth і Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Выберыце прыладу (<xliff:g id="APP_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма &lt;strong&gt;&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Выберыце імя <xliff:g id="PROFILE_NAME">%1$s</xliff:g> для наладжвання"</string>
- <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>: ідзе пошук"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>: выберыце, каб наладзіць"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Ідзе пошук: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Гэта праграма зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць) на вашай прыладзе тыпу \"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>\" і атрымае наступныя дазволы"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; кіраваць прыладай &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"прылада"</string>
@@ -63,7 +63,7 @@
<string name="permission_microphone" msgid="2152206421428732949">"Мікрафон"</string>
<string name="permission_call_logs" msgid="5546761417694586041">"Журналы выклікаў"</string>
<string name="permission_nearby_devices" msgid="7530973297737123481">"Прылады паблізу"</string>
- <string name="permission_media_routing_control" msgid="5498639511586715253">"Змяніць прыладу вываду медыя"</string>
+ <string name="permission_media_routing_control" msgid="5498639511586715253">"Змяненне прылады вываду медыя"</string>
<string name="permission_storage" msgid="6831099350839392343">"Фота і медыяфайлы"</string>
<string name="permission_notifications" msgid="4099418516590632909">"Апавяшчэнні"</string>
<string name="permission_phone_summary" msgid="8246321093970051702">"Ажыццяўленне тэлефонных выклікаў і кіраванне імі"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index e7f9b146133e..bc74b1aaefbc 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -25,7 +25,7 @@
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth i WiFi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da postavite"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Odaberite <xliff:g id="PROFILE_NAME">%1$s</xliff:g> za postavljanje"</string>
<string name="single_device_title" msgid="4199861437545438606">"Traži se <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Aplikaciji će biti dozvoljeno da sinhronizira informacije, kao što je ime osobe koja upućuje poziv, i pristupa ovim odobrenjima koje sadržava vaš <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Dozvoliti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index 08a1ae1a8623..1062af845c9f 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -26,7 +26,7 @@
<string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Vælg en enhed, som skal administreres af &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Vælg en <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, som du vil konfigurere"</string>
- <string name="single_device_title" msgid="4199861437545438606">"Søger efter et <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Søger efter <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Denne app får tilladelse til at synkronisere oplysninger, f.eks. navne på dem, der ringer, og adgang til disse tilladelser på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du tillade, at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administrerer &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"enhed"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 30528c528518..6f8a902edc91 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Begleitgerät-Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Zulassen, dass &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; auf &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; zugreifen darf?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Achte darauf, dass die Option „<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>“ auf diesem <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> aktiviert ist und dein Begleitgerät vom Typ „<xliff:g id="PROFILE_NAME">%3$s</xliff:g>“ in der Nähe ist."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> muss auf diesem <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> aktiviert und dein Gerät „<xliff:g id="PROFILE_NAME">%3$s</xliff:g>“ in der Nähe sein."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Keine Geräte gefunden. Bitte versuche es später noch einmal."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"WLAN"</string>
@@ -26,7 +26,7 @@
<string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Gerät auswählen, das von &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; verwaltet werden soll"</string>
<string name="chooser_title" msgid="2235819929238267637">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> zum Einrichten auswählen"</string>
- <string name="single_device_title" msgid="4199861437545438606">"Nach einem Begleitgerät vom Typ „<xliff:g id="PROFILE_NAME">%1$s</xliff:g>“ suchen"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> wird gesucht"</string>
<string name="summary_watch" msgid="8134580124808507407">"Diese App darf dann Daten wie den Namen eines Anrufers synchronisieren und auf diese Berechtigungen auf deinem Gerät (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) zugreifen"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Zulassen, dass &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; das Gerät &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; verwalten darf?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"Gerät"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index cffb365974f4..c90bf21c87ab 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -18,16 +18,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Διαχείριση συνοδευτικής εφαρμογής"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να έχει πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;;"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Βεβαιωθείτε ότι αυτή η συσκευή <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> έχει ενεργοποιημένο το <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> και κρατήστε τη συσκευή <xliff:g id="PROFILE_NAME">%3$s</xliff:g> κοντά."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Βεβαιωθείτε ότι αυτό το <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> έχει ενεργοποιημένο το <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> και κρατήστε το <xliff:g id="PROFILE_NAME">%3$s</xliff:g> κοντά."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Δεν βρέθηκαν συσκευές. Δοκιμάστε ξανά αργότερα."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth και Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Επιλέξτε μια συσκευή για διαχείριση μέσω της εφαρμογής &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για ρύθμιση"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Επιλέξτε ένα <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για ρύθμιση"</string>
<string name="single_device_title" msgid="4199861437545438606">"Αναζήτηση για <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="8134580124808507407">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες, όπως το όνομα ενός ατόμου που σας καλεί, και να αποκτά πρόσβαση σε αυτές τις άδειες στη συσκευή <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες, όπως το όνομα ενός ατόμου που σας καλεί, και να αποκτά πρόσβαση σε αυτές τις άδειες στο <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να διαχειρίζεται τη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ;"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"συσκευή"</string>
<string name="summary_glasses" msgid="5469208629679579157">"Αυτή η εφαρμογή θα μπορεί να έχει πρόσβαση σε αυτές τις άδειες στη συσκευή <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index ac8c79a61496..a309d7cb4d27 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -46,7 +46,7 @@
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tendrá acceso a todo lo que se reproduzca en tu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> podrá emitir audio en <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hasta que quites el acceso a este permiso."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para emitir audio y funciones del sistema en otros dispositivos tuyos."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
- <string name="summary_generic" msgid="1761976003668044801">"Esta aplicación podrá sincronizar información (por ejemplo, el nombre de la persona que te llama) entre tu teléfono y el dispositivo que elijas"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"Esta aplicación podrá sincronizar información, como el nombre de la persona que llama, entre tu teléfono y el dispositivo que elijas"</string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
<string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 9c22847df868..91d1b6914e23 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -18,16 +18,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Kaasseadme haldur"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Kas anda rakendusele &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; juurdepääs seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Veenduge, et seadmes <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> oleks <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> sisse lülitatud, ja hoidke oma seade <xliff:g id="PROFILE_NAME">%3$s</xliff:g> läheduses."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Veenduge, et seadmes <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> oleks <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> sisse lülitatud, ja hoidke oma <xliff:g id="PROFILE_NAME">%3$s</xliff:g> läheduses."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Seadmeid ei leitud. Proovige hiljem uuesti."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"WiFi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth ja WiFi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
- <string name="chooser_title_non_profile" msgid="6035023914517087400">"Valige seade, mida haldab rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Valige <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mis seadistada"</string>
- <string name="single_device_title" msgid="4199861437545438606">"Seadme <xliff:g id="PROFILE_NAME">%1$s</xliff:g> otsimine"</string>
- <string name="summary_watch" msgid="8134580124808507407">"Sellel rakendusel lubatakse sünkroonida teavet (nt helistaja nime) ja antakse juurdepääs nendele lubadele, mille asukoht on teie <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Valige seade, mida rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hakkab haldama"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Valige seadistatav <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Otsimine: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"Sellel rakendusel lubatakse sünkroonida teavet (nt helistaja nime) ja antakse juurdepääs nendele teie seadme <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> lubadele."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hallata seadet &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"seade"</string>
<string name="summary_glasses" msgid="5469208629679579157">"Sellel rakendusel lubatakse juurde pääseda nendele lubadele, mille asukoht on teie <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
@@ -46,7 +46,7 @@
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Rakendus <xliff:g id="APP_NAME_0">%1$s</xliff:g> saab juurdepääsu kõigele, mida teie seadmes <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> esitatakse.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> saab edastada heli seadmesse <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, kuni selle loa eemaldate."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel heli ja süsteemifunktsioonide edastamiseks."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
- <string name="summary_generic" msgid="1761976003668044801">"See rakendus saab sünkroonida teavet, näiteks helistaja nime, teie telefoni ja valitud seadme vahel"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"See rakendus saab sünkroonida teavet (näiteks helistaja nime) teie telefoni ja valitud seadme vahel."</string>
<string name="consent_yes" msgid="8344487259618762872">"Luba"</string>
<string name="consent_no" msgid="2640796915611404382">"Ära luba"</string>
<string name="consent_cancel" msgid="5655005528379285841">"Tühista"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 2f4f9380171e..048bf3e7b0b4 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -24,7 +24,7 @@
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"‏بلوتوث و Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
- <string name="chooser_title_non_profile" msgid="6035023914517087400">"‏انتخاب دستگاه برای مدیریت کردن با &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"‏انتخاب دستگاه برای مدیریت شدن توسط &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای راه‌اندازی"</string>
<string name="single_device_title" msgid="4199861437545438606">"درحال یافتن <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"به این برنامه اجازه داده می‌شود اطلاعاتی مثل نام تماس‌گیرنده را همگام‌سازی کند و به این اجازه‌ها در <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> شما دسترسی داشته باشد"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index be4076abde4b..3f4a9d3cc1e0 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/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="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="2244241995958340998">"Sallitaanko, että soellus (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;) saa pääsyn laitteeseen: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Sallitaanko, että sovellus (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;) saa pääsyn laitteeseen: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="message_discovery_soft_timeout" msgid="473346859407859161">"Varmista, että <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> on päällä laitteella (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>), ja pidä <xliff:g id="PROFILE_NAME">%3$s</xliff:g> lähellä."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Laitteita ei löydy. Yritä myöhemmin uudelleen."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 0aa462bee90e..52b136c0c322 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -18,15 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareil compagnon"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Autoriser l\'appli &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Assurez-vous que le <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> est activé sur cet appareil (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) et gardez votre <xliff:g id="PROFILE_NAME">%3$s</xliff:g> à proximité."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Assurez-vous que le <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> est activé sur votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> et gardez votre <xliff:g id="PROFILE_NAME">%3$s</xliff:g> à proximité."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Aucun appareil détecté. Veuillez réessayer plus tard."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth et Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Choisir un appareil qui sera géré par &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Choisir un appareil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) pour le configurer"</string>
- <string name="single_device_title" msgid="4199861437545438606">"À la recherche de l\'appareil suivant : <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Choisir votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g> à configurer"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Recherche de votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Cette appli sera autorisée à synchroniser des informations, comme le nom de l\'appelant, et à accéder à ces autorisations sur votre <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à gérer &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"appareil"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index d3db96eedb6b..9df54dac3470 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"કમ્પેનિયન ડિવાઇસ મેનેજર"</string>
<string name="confirmation_title" msgid="2244241995958340998">"શું &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ઍપને મંજૂરી આપીએ?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ખાતરી કરો કે આ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> દ્વારા <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ચાલુ કરવામાં આવી છે અને તમારી <xliff:g id="PROFILE_NAME">%3$s</xliff:g> નજીકમાં રાખો."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ખાતરી કરો કે આ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> દ્વારા <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ચાલુ કરવામાં આવ્યું છે અને તમારી <xliff:g id="PROFILE_NAME">%3$s</xliff:g> નજીકમાં રાખો."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"કોઈ ડિવાઇસ મળ્યું નથી. કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"બ્લૂટૂથ"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"વાઇ-ફાઇ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 2d38a00e9fcb..fe04cbd3503f 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -17,8 +17,8 @@
<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="4470785958457506021">"कंपैनियन डिवाइस मैनेजर"</string>
- <string name="confirmation_title" msgid="2244241995958340998">"क्या &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; को ऐक्सेस करने के लिए &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ऐप्लिकेशन को अनुमति देनी है?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"पक्का करें कि इस <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> का <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> चालू हो और <xliff:g id="PROFILE_NAME">%3$s</xliff:g> आपके आस-पास हो."</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"क्या &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ऐप्लिकेशन को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ऐक्सेस करने की अनुमति देनी है?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"पक्का करें कि इस <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> का <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> चालू हो और <xliff:g id="PROFILE_NAME">%3$s</xliff:g> आस-पास हो."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"कोई डिवाइस नहीं मिला. कृपया बाद में कोशिश करें."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"ब्लूटूथ"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"वाई-फ़ाई"</string>
@@ -27,7 +27,7 @@
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; से मैनेज किया जाने वाला डिवाइस चुनें"</string>
<string name="chooser_title" msgid="2235819929238267637">"सेट अप करने के लिए कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें"</string>
<string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> को ढूंढा जा रहा है"</string>
- <string name="summary_watch" msgid="8134580124808507407">"यह ऐप्लिकेशन, आपके <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस करने के साथ-साथ कॉल करने वाले व्यक्ति के नाम जैसी जानकारी सिंक कर पाएगा"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"यह ऐप्लिकेशन, कॉल करने वाले व्यक्ति के नाम जैसी जानकारी सिंक करने के साथ-साथ, आपके <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस कर पाएगा"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"क्या &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; मैनेज करने की अनुमति देनी है?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"डिवाइस"</string>
<string name="summary_glasses" msgid="5469208629679579157">"यह ऐप्लिकेशन, आपके <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस कर पाएगा"</string>
@@ -63,7 +63,7 @@
<string name="permission_microphone" msgid="2152206421428732949">"माइक्रोफ़ोन"</string>
<string name="permission_call_logs" msgid="5546761417694586041">"कॉल लॉग"</string>
<string name="permission_nearby_devices" msgid="7530973297737123481">"आस-पास मौजूद डिवाइस"</string>
- <string name="permission_media_routing_control" msgid="5498639511586715253">"मीडिया आउटपुट में बदलाव करे"</string>
+ <string name="permission_media_routing_control" msgid="5498639511586715253">"मीडिया आउटपुट में बदलाव"</string>
<string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string>
<string name="permission_notifications" msgid="4099418516590632909">"सूचनाएं"</string>
<string name="permission_phone_summary" msgid="8246321093970051702">"फ़ोन कॉल करने और उन्हें मैनेज करने की अनुमति दें"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 8b11dac56f9c..9fb92c31b836 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -18,16 +18,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Társeszközök kezelője"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazás számára, hogy hozzáférjen a következőhöz: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Győződjön meg arról, hogy a <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> be van kapcsolva ezen a(z) <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> eszközön, és hogy a(z) <xliff:g id="PROFILE_NAME">%3$s</xliff:g> eszköz a közelben van."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Győződjön meg arról, hogy a <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> be van kapcsolva a(z) <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>, és hogy a(z) <xliff:g id="PROFILE_NAME">%3$s</xliff:g> a közelben van."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nem található eszköz. Próbálja újra később."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth és Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazással kezelni kívánt eszköz kiválasztása"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Válassza ki a beállítani kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> nevet."</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Válassza ki a beállítani kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> nevét."</string>
<string name="single_device_title" msgid="4199861437545438606">"Keresés – <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="8134580124808507407">"Ez az alkalmazás képes lesz szinkronizálni információkat (például a hívó fél nevét), és hozzáférhet majd ezekhez az engedélyekhez a következőn: <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"Ez az alkalmazás képes lesz szinkronizálni információkat (például a hívó fél nevét), és hozzáférhet majd ezekhez az engedélyekhez a <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Engedélyezi, hogy a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; kezelje a következő eszközt: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"eszköz"</string>
<string name="summary_glasses" msgid="5469208629679579157">"Az alkalmazás hozzáférhet majd ezekhez az engedélyekhez a következőn: <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index 9d45928eeb5f..b398b94c0c3f 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -18,15 +18,15 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին կառավարել &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքը"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Համոզվեք, որ այս <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> սարքի <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>-ը միացված է, և ձեր <xliff:g id="PROFILE_NAME">%3$s</xliff:g>-ը մոտ պահեք։"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Համոզվեք, որ այս <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ի <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>-ը միացված է, և ձեր <xliff:g id="PROFILE_NAME">%3$s</xliff:g>ը մոտ պահեք։"</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Սարքեր չեն գտնվել։ Փորձեք ավելի ուշ։"</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth և Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Ընտրեք սարքը, որը պետք է կառավարվի &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածի միջոցով"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Կարգավորելու համար ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը"</string>
- <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> սարքի որոնում"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Կարգավորելու համար ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Որոնվում է <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Այս հավելվածը կկարողանա համաժամացնել տվյալները, օր․՝ զանգողի անունը, և կստանա հետևյալ թույլտվությունները ձեր <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ում"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին կառավարել &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքը"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"սարք"</string>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 3fa0419832e8..36647ada789c 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -27,7 +27,7 @@
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Scegli un dispositivo che sia gestito da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da configurare"</string>
<string name="single_device_title" msgid="4199861437545438606">"Ricerca di un <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="8134580124808507407">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, e accedere alle seguenti autorizzazioni <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, e accedere alle seguenti autorizzazioni sul <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vuoi consentire all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di gestire &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>
<string name="summary_glasses" msgid="5469208629679579157">"Questa app potrà accedere alle seguenti autorizzazioni <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>:"</string>
@@ -46,7 +46,7 @@
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> avrà accesso a tutto ciò che viene riprodotto sul tuo <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> sarà in grado di riprodurre in streaming l\'audio su <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> finché non rimuoverai l\'accesso a questa autorizzazione."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede l\'autorizzazione per conto di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per riprodurre in streaming funzionalità di sistema e audio tra i tuoi dispositivi."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
- <string name="summary_generic" msgid="1761976003668044801">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, tra il telefono e il dispositivo scelto"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, tra lo smartphone e il dispositivo scelto"</string>
<string name="consent_yes" msgid="8344487259618762872">"Consenti"</string>
<string name="consent_no" msgid="2640796915611404382">"Non consentire"</string>
<string name="consent_cancel" msgid="5655005528379285841">"Annulla"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index f775a7f16f81..f08ee6e674d2 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -27,7 +27,7 @@
<string name="chooser_title_non_profile" msgid="6035023914517087400">"‏בחירה של מכשיר לניהול באמצעות &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> להגדרה"</string>
<string name="single_device_title" msgid="4199861437545438606">"מתבצע חיפוש של <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="8134580124808507407">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, ולגשת להרשאות האלה ב<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> שלך"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מי שמתקשר, ולגשת להרשאות האלה ב<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> שלך"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"‏מתן הרשאה לאפליקציה ‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&amp;g;‎‏ לנהל את ‎&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‎‏"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"מכשיר"</string>
<string name="summary_glasses" msgid="5469208629679579157">"האפליקציה הזו תוכל לגשת להרשאות האלה ב<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> שלך"</string>
@@ -46,7 +46,7 @@
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"‏לאפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> תהיה גישה לכל מה שיופעל במכשיר <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.&lt;br/&gt;&lt;br/&gt;האפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> תוכל לשדר אודיו אל <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> עד שההרשאה הזו תוסר."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת בשם <xliff:g id="DEVICE_NAME">%2$s</xliff:g> הרשאה כדי לשדר תכונות מערכת ואודיו בין המכשירים שלך."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
- <string name="summary_generic" msgid="1761976003668044801">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, מהטלפון שלך למכשיר שבחרת"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מי שמתקשר, בין הטלפון שלך למכשיר שבחרת"</string>
<string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string>
<string name="consent_no" msgid="2640796915611404382">"אין אישור"</string>
<string name="consent_cancel" msgid="5655005528379285841">"ביטול"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index d9bc50a4f9f5..3fb5519b8177 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -26,7 +26,7 @@
<string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"აირჩიეთ მოწყობილობა, რომელიც უნდა მართოს &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; აპმა"</string>
<string name="chooser_title" msgid="2235819929238267637">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> დასაყენებლად"</string>
- <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-ის ძებნა"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"იძებნება <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"ეს აპი შეძლებს ინფორმაციის (მაგალითად, იმ ადამიანის სახელი, რომელიც გირეკავთ) სინქრონიზებას და თქვენს <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>-ზე არსებულ ამ ნებართვებზე წვდომას"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"ნება დართეთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ს&lt;/strong&gt; მართოს &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"მოწყობილობა"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 2fd8d96dfd7f..06b82ec171ee 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -17,16 +17,16 @@
<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="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;? құрылғысына кіруге рұқсат беріңіз"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Құрылғыдағы (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> қосулы болуын тексеріп, <xliff:g id="PROFILE_NAME">%3$s</xliff:g> құрылғысын маңайында ұстаңыз."</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысының дерегін пайдалануға рұқсат беру керек пе?"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Құрылғыдағы (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> қосулы болуын тексеріп, <xliff:g id="PROFILE_NAME">%3$s</xliff:g> одан алыстамауын қадағалаңыз."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Ешқандай құрылғы табылмады. Кейінірек қайталап көріңіз."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth және Wi-Fi"</string>
- <string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
+ <string name="profile_name_watch" msgid="576290739483672360">"Сағат"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; арқылы басқарылатын құрылғыны таңдаңыз"</string>
<string name="chooser_title" msgid="2235819929238267637">"Реттеу үшін <xliff:g id="PROFILE_NAME">%1$s</xliff:g> таңдаңыз"</string>
- <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын іздеу"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ізделіп жатыр"</string>
<string name="summary_watch" msgid="8134580124808507407">"Бұл қолданба қоңырау шалушының аты сияқты деректі синхрондай алады және құрылғыдағы (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) осы рұқсаттарды пайдалана алады."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысын басқаруға рұқсат беру керек пе?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"құрылғы"</string>
@@ -45,7 +45,7 @@
<string name="title_sensor_device_streaming" msgid="2395553261097861497">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> құрылғыңыз бен &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; құрылғысы арасында аудио және жүйе функцияларын трансляциялауға рұқсат берілсін бе?"</string>
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> құрылғыңызда ойнатылатын барлық контентті пайдалана алады.&lt;br/&gt;&lt;br/&gt;Бұл рұқсатты өшірмесеңіз, <xliff:g id="APP_NAME_2">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> құрылғысына аудионы трансляциялай алады."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан құрылғыларыңыз арасында аудио және жүйе функцияларын трансляциялауға рұқсат сұрайды."</string>
- <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
+ <string name="profile_name_generic" msgid="6851028682723034988">"Құрылғы"</string>
<string name="summary_generic" msgid="1761976003668044801">"Бұл қолданба телефон мен таңдалған құрылғы арасында деректі (мысалы, қоңырау шалушының атын) синхрондай алады."</string>
<string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string>
<string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 8320708da102..269d729db9b1 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -17,13 +17,13 @@
<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="4470785958457506021">"ಕಂಪ್ಯಾನಿಯನ್ ಸಾಧನ ನಿರ್ವಾಹಕರು"</string>
- <string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸಬೇಕೆ?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಬೇಕೆ?"</string>
<string name="message_discovery_soft_timeout" msgid="473346859407859161">"ಈ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ನಲ್ಲಿ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ಆನ್ ಆಗಿದೆಯೇ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ ಮತ್ತು ನಿಮ್ಮ <xliff:g id="PROFILE_NAME">%3$s</xliff:g> ಅನ್ನು ಸಮೀಪಲ್ಲಿಡಿ."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"ಯಾವುದೇ ಸಾಧನಗಳು ಕಂಡುಬಂದಿಲ್ಲ. ನಂತರ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"ಬ್ಲೂಟೂತ್"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"ವೈ-ಫೈ"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"ಬ್ಲೂಟೂತ್ ಮತ್ತು ವೈ-ಫೈ"</string>
- <string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
+ <string name="profile_name_watch" msgid="576290739483672360">"ವಾಚ್"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ ಸಾಧನವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="chooser_title" msgid="2235819929238267637">"ಸೆಟಪ್ ಮಾಡಲು <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆರಿಸಿ"</string>
<string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index af01cf7c8d7d..a7b4f40eecd1 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүнө кирүүгө уруксат бересизби?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> түзмөгүңүздөгү <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>ыкмасын күйгүзүп, <xliff:g id="PROFILE_NAME">%3$s</xliff:g> профилиңизди жакын кармаңыз."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"<xliff:g id="DEVICE_TYPE">%1$s</xliff:g> түзмөгүңүз <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> аркылуу башка түзмөктөр менен байланыша аларын текшериңиз. <xliff:g id="PROFILE_NAME">%3$s</xliff:g> жакын кармаңыз."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Түзмөктөр табылган жок. Кийинчерээк кайталап көрүңүз."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
@@ -26,7 +26,7 @@
<string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; аркылуу башкарыла турган түзмөктү тандаңыз"</string>
<string name="chooser_title" msgid="2235819929238267637">"Тууралоо үчүн <xliff:g id="PROFILE_NAME">%1$s</xliff:g> тандаңыз"</string>
- <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> профилин издөө"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Түзмөк издөө (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>)"</string>
<string name="summary_watch" msgid="8134580124808507407">"Бул колдонмого маалыматты, мисалы, чалып жаткан адамдын аты-жөнүн шайкештирүүгө жана <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> түзмөгүңүздө төмөнкүлөрдү аткарууга уруксат берилет"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүн тескөөгө уруксат бересизби?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"түзмөк"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 9fcf0fa22c67..5dd1d06d545e 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -26,7 +26,7 @@
<string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Įrenginio, kuris bus valdomas naudojant programą &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, pasirinkimas"</string>
<string name="chooser_title" msgid="2235819929238267637">"Norimo nustatyti <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pasirinkimas"</string>
- <string name="single_device_title" msgid="4199861437545438606">"Ieškoma <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Ieškoma: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Šiai programai bus leidžiama sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, ir pasiekti toliau nurodytus <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> leidimus"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; valdyti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"įrenginio"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 39b158d58666..40de5d1afad4 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Palīgierīču pārzinis"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt lietotnei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Noteikti ieslēdziet šajā ierīcē (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> un gādājiet, lai <xliff:g id="PROFILE_NAME">%3$s</xliff:g> būtu tuvumā."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Pārliecinieties, vai <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> var izveidot savienojumu ar citām ierīcēm ar <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, un gādājiet, lai <xliff:g id="PROFILE_NAME">%3$s</xliff:g> būtu tuvumā."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nav atrasta neviena ierīce. Lūdzu, vēlāk mēģiniet vēlreiz."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi‑Fi"</string>
@@ -26,7 +26,7 @@
<string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Izvēlieties ierīci, ko pārvaldīt lietotnē &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Jāizvēlas <xliff:g id="PROFILE_NAME">%1$s</xliff:g> iestatīšanai"</string>
- <string name="single_device_title" msgid="4199861437545438606">"Tiek meklēta ierīce (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>)…"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Tiek meklēts <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Šī lietotne drīkstēs sinhronizēt informāciju, piemēram, zvanītāja vārdu, un piekļūt šīm <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> atļaujām."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vai atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt ierīcei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"ierīce"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 107895d5a8da..db1c06a78b55 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/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="4470785958457506021">"Companion Device Manager"</string>
- <string name="confirmation_title" msgid="2244241995958340998">"Дозволувате апликацијата &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"Дали дозволувате апликацијата &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="message_discovery_soft_timeout" msgid="473346859407859161">"Погрижете се <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> да биде вклучен на овој <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> и вашиот <xliff:g id="PROFILE_NAME">%3$s</xliff:g> да биде во близина."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Не се најдени уреди. Обидете се повторно подоцна."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
@@ -77,8 +77,8 @@
<string name="permission_notifications_summary" msgid="2272810466047367030">"• Ги чита сите известувања, меѓу кои и податоци како контакти, пораки и фотографии&lt;br/&gt;• Испраќа известувања&lt;br/&gt;&lt;br/&gt;Може да управувате со способноста на апликацијава да чита и испраќа известувања кога било во „Поставки &gt; Известувања“."</string>
<string name="permission_storage_summary" msgid="3918240895519506417"></string>
<string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Пристап до списокот со достапни уреди и контрола кои стримуваат или емитуваат аудио или видео од други апликации"</string>
- <string name="device_type" product="default" msgid="8268703872070046263">"Телефон"</string>
- <string name="device_type" product="tablet" msgid="5038791954983067774">"Таблет"</string>
+ <string name="device_type" product="default" msgid="8268703872070046263">"телефон"</string>
+ <string name="device_type" product="tablet" msgid="5038791954983067774">"таблет"</string>
<string name="device_type" product="tv" msgid="5355611506659405636">"ТВ"</string>
<string name="device_type" product="device" msgid="1526125965802507189">"уред"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 722156213623..03a5271df0d6 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिव्हाइस व्यवस्थापक"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; अ‍ॅपला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"या <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> चे <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> सुरू असल्याची खात्री करा आणि तुमचे<xliff:g id="PROFILE_NAME">%3$s</xliff:g> जवळ ठेवा."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"या <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> चे <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> सुरू असल्याची खात्री करा आणि तुमचे <xliff:g id="PROFILE_NAME">%3$s</xliff:g> जवळ ठेवा."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"डिव्हाइस आढळली नाहीत. कृपया नंतर पुन्हा प्रयत्न करा."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"ब्लूटूथ"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"वाय-फाय"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 1d62349da406..6008299e1ee0 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -18,16 +18,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vil du gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-appen tilgang til &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Sørg for at <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> har <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> slått på, og hold <xliff:g id="PROFILE_NAME">%3$s</xliff:g> i nærheten."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Sørg for at denne enheten (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>) har <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> slått på, og hold den andre enheten (<xliff:g id="PROFILE_NAME">%3$s</xliff:g>) i nærheten."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Fant ingen enheter. Prøv på nytt senere."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wifi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth og wifi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Velg en enhet som skal administreres av &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal konfigureres"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Velg enheten (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) som skal konfigureres"</string>
<string name="single_device_title" msgid="4199861437545438606">"Ser etter en <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="8134580124808507407">"Denne appen får tillatelse til å synkronisere informasjon, for eksempel navnet til folk som ringer, og har disse tillatelsene på <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"Denne appen får tillatelse til å synkronisere informasjon, for eksempel navnet til folk som ringer, og har disse tillatelsene på enheten din (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du la &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; administrere &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"enheten"</string>
<string name="summary_glasses" msgid="5469208629679579157">"Denne appen får disse tillatelsene på <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 694abdd20814..dd8b1ae345ec 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -18,16 +18,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिभाइसको प्रबन्धक"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; एपलाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रयोग गर्ने अनुमति दिने हो?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"यो <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> को <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> अन गरिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस् अनि आफ्नो <xliff:g id="PROFILE_NAME">%3$s</xliff:g> नजिकै राख्नुहोस्।"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"यो <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>को <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> अन गरिएको छ भन्ने कुरा सुनिश्चित गर्नुहोस् अनि आफ्नो <xliff:g id="PROFILE_NAME">%3$s</xliff:g> नजिकै राख्नुहोस्।"</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"कुनै पनि डिभाइस भेटिएन। कृपया पछि फेरि प्रयास गर्नुहोस्।"</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"ब्लुटुथ"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"ब्लुटुथ तथा Wi-Fi"</string>
- <string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
+ <string name="profile_name_watch" msgid="576290739483672360">"स्मार्ट वाच"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"आफूले &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; प्रयोग गरी व्यवस्थापन गर्न चाहेको डिभाइस चयन गर्नुहोस्"</string>
<string name="chooser_title" msgid="2235819929238267637">"सेट अप गर्नका लागि <xliff:g id="PROFILE_NAME">%1$s</xliff:g> छनौट गर्नुहोस्"</string>
<string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> खोजिँदै छ"</string>
- <string name="summary_watch" msgid="8134580124808507407">"तपाईंको <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> मा यो एपलाई कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्ने र यी कुराहरू गर्ने अनुमति दिइने छ"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"तपाईंको <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>मा यो एपलाई कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्ने र निम्न कुरासँग सम्बन्धित अनुमतिहरू दिइने छ"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; व्यवस्थापन गर्ने अनुमति दिने हो?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"डिभाइस"</string>
<string name="summary_glasses" msgid="5469208629679579157">"तपाईंको <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> मा यो एपलाई निम्न अनुमति दिइने छ:"</string>
@@ -45,8 +45,8 @@
<string name="title_sensor_device_streaming" msgid="2395553261097861497">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> र &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; का बिचमा अडियो र सिस्टमका सुविधाहरू स्ट्रिम गर्ने अनुमति दिने हो?"</string>
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ले तपाईंको <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> मा प्ले गरिने सबै कुरा एक्सेस गर्न सक्ने छ।&lt;br/&gt;&lt;br/&gt;तपाईंले यो अनुमति रद्द नगरेसम्म <xliff:g id="APP_NAME_2">%1$s</xliff:g> ले <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> मा अडियो स्ट्रिम गर्न पाइराख्ने छ।"</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले डिभाइस <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट तपाईंका डिभाइसहरूका बिचमा अडियो र सिस्टमका सुविधाहरू स्ट्रिम गर्ने अनुमति माग्दै छ।"</string>
- <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string>
- <string name="summary_generic" msgid="1761976003668044801">"यो एपले तपाईंको फोन र तपाईंले छनौट गर्ने डिभाइसका बिचमा कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्न सक्ने छ।"</string>
+ <string name="profile_name_generic" msgid="6851028682723034988">"डिभाइस"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"यो एपले तपाईंको फोन र छनौट गरिएको डिभाइसका बिचमा कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्न सक्ने छ"</string>
<string name="consent_yes" msgid="8344487259618762872">"अनुमति दिनुहोस्"</string>
<string name="consent_no" msgid="2640796915611404382">"अनुमति नदिनुहोस्"</string>
<string name="consent_cancel" msgid="5655005528379285841">"रद्द गर्नुहोस्"</string>
@@ -63,7 +63,7 @@
<string name="permission_microphone" msgid="2152206421428732949">"माइक्रोफोन"</string>
<string name="permission_call_logs" msgid="5546761417694586041">"कल लगहरू"</string>
<string name="permission_nearby_devices" msgid="7530973297737123481">"नजिकैका डिभाइसहरू"</string>
- <string name="permission_media_routing_control" msgid="5498639511586715253">"मिडिया आउटपुट बदल्नुहोस्"</string>
+ <string name="permission_media_routing_control" msgid="5498639511586715253">"मिडिया आउटपुट बदल्ने"</string>
<string name="permission_storage" msgid="6831099350839392343">"फोटो र मिडिया"</string>
<string name="permission_notifications" msgid="4099418516590632909">"नोटिफिकेसनहरू"</string>
<string name="permission_phone_summary" msgid="8246321093970051702">"फोन कल गर्ने र व्यवस्थापन गर्ने"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 5e389611eaa4..22feb9deca17 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -46,7 +46,7 @@
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> krijgt toegang tot alles wat wordt afgespeeld op je <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> kan audio naar <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> streamen totdat je de toegang tot dit recht intrekt."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om audio en systeemfuncties te streamen tussen je apparaten."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
- <string name="summary_generic" msgid="1761976003668044801">"Deze app kan informatie, zoals de naam van iemand die belt, synchroniseren tussen je telefoon en het gekozen apparaat"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"Deze app kan informatie synchroniseren (zoals de naam van iemand die belt) tussen je telefoon en het gekozen apparaat"</string>
<string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string>
<string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string>
<string name="consent_cancel" msgid="5655005528379285841">"Annuleren"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index 14dcc18a532d..96c62070ee62 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"ସହଯୋଗୀ ଡିଭାଇସ୍ ପରିଚାଳକ"</string>
<string name="confirmation_title" msgid="2244241995958340998">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ଆପକୁ ଅନୁମତି ଦେବେ?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ସୁନିଶ୍ଚିତ ହୁଏନ୍ତୁ ଏହି <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ରେ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ଚାଲୁ କରାଯାଇଛି ଏବଂ ଆପଣଙ୍କର <xliff:g id="PROFILE_NAME">%3$s</xliff:g> ଆଖପାଖରେ ରଖନ୍ତୁ।"</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"ସୁନିଶ୍ଚିତ ହୁଏନ୍ତୁ ଯେ ଏହି <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>ରେ <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ଚାଲୁ କରାଯାଇଛି ଏବଂ ଆପଣଙ୍କର <xliff:g id="PROFILE_NAME">%3$s</xliff:g> ଆଖପାଖରେ ରଖନ୍ତୁ।"</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"କୌଣସି ଡିଭାଇସ ମିଳିଲା ନାହିଁ। ଦୟାକରି ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"ବ୍ଲୁଟୁଥ"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"ୱାଇ-ଫାଇ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 90bc1e3bc34b..62a0d407d7ad 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -18,14 +18,14 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menedżer urządzeń towarzyszących"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do urządzenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Upewnij się, że <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ma włączoną funkcję <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, i trzymaj urządzenie <xliff:g id="PROFILE_NAME">%3$s</xliff:g> w pobliżu."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Upewnij się, że <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> ma włączoną funkcję <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, i trzymaj <xliff:g id="PROFILE_NAME">%3$s</xliff:g> w pobliżu."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nie znaleziono urządzeń. Spróbuj ponownie później."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth i Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Wybierz urządzenie, którym ma zarządzać aplikacja &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, aby go skonfigurować"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Wybierz <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, aby go skonfigurować"</string>
<string name="single_device_title" msgid="4199861437545438606">"Szukam: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Aplikacja będzie mogła synchronizować informacje takie jak nazwa dzwoniącego oraz korzystać z tych uprawnień na Twoim urządzeniu (<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>)"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Zezwolić na dostęp aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; do urządzenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 073fa260c401..81c50c1c9142 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Confira se o <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> tem o <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ativado e se o <xliff:g id="PROFILE_NAME">%3$s</xliff:g> está por perto."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Confira se o <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> está com o <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ativado e se o <xliff:g id="PROFILE_NAME">%3$s</xliff:g> está por perto."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nenhum dispositivo foi encontrado. Tente de novo mais tarde."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 073fa260c401..81c50c1c9142 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Confira se o <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> tem o <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ativado e se o <xliff:g id="PROFILE_NAME">%3$s</xliff:g> está por perto."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Confira se o <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> está com o <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> ativado e se o <xliff:g id="PROFILE_NAME">%3$s</xliff:g> está por perto."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nenhum dispositivo foi encontrado. Tente de novo mais tarde."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 42acfb7a4d36..a5b5b594608c 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -46,7 +46,7 @@
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Приложение \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" получит доступ ко всему, что воспроизводится на устройстве \"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>\".&lt;br/&gt;&lt;br/&gt;Приложение \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" сможет транслировать аудио на устройство \"<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>\", пока вы не отзовете это разрешение."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать аудио и системные функции между устройствами."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
- <string name="summary_generic" msgid="1761976003668044801">"Приложение сможет синхронизировать информацию между телефоном и выбранным устройством, например данные из журнала звонков."</string>
+ <string name="summary_generic" msgid="1761976003668044801">"Приложение сможет синхронизировать информацию между телефоном и выбранным устройством, например имя того, кто вам звонит."</string>
<string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string>
<string name="consent_no" msgid="2640796915611404382">"Запретить"</string>
<string name="consent_cancel" msgid="5655005528379285841">"Отмена"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 9ee2ce574cc0..f46252eda366 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -25,7 +25,7 @@
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth a Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Vyberte zariadenie, ktoré bude spravovať aplikácia &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý nastavíte"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý chcete nastaviť"</string>
<string name="single_device_title" msgid="4199861437545438606">"Hľadá sa zariadenie <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, a získavať prístup k týmto povoleniam v zariadení <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Chcete povoliť aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; spravovať zariadenie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 3d08276d0e19..0696c986d3a4 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -18,16 +18,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Upravitelj spremljevalnih naprav"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Želite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoliti dostop do naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Poskrbite, da je v napravi <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> vklopljena nastavitev »<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>«, in napravo <xliff:g id="PROFILE_NAME">%3$s</xliff:g> imejte v bližini."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Poskrbite, da ima <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> vklopljen <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>, <xliff:g id="PROFILE_NAME">%3$s</xliff:g> pa naj bo v bližini."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Ni naprav. Poskusite znova pozneje."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth in Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Izbira naprave, ki jo bo upravljala aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Izberite profil naprave »<xliff:g id="PROFILE_NAME">%1$s</xliff:g>« za nastavitev"</string>
- <string name="single_device_title" msgid="4199861437545438606">"Iskanje naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="8134580124808507407">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, in dostopala do teh dovoljenj v napravi »<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>«."</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Izberite za nastavitev: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Iskanje: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, in dostopala do teh dovoljenj v: <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>."</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Želite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoliti upravljanje naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"naprava"</string>
<string name="summary_glasses" msgid="5469208629679579157">"Ta aplikacija bo lahko dostopala do teh dovoljenj v napravi »<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>«."</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index de3232201da0..02f88ce11637 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -18,12 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Menaxheri i pajisjes shoqëruese"</string>
<string name="confirmation_title" msgid="2244241995958340998">"T\'i lejohet aplikacionit &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; qasja te &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Sigurohu që ky <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> të ketë të aktivizuar<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> dhe mbaje <xliff:g id="PROFILE_NAME">%3$s</xliff:g> tënde pranë."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Sigurohu që ky <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> të ketë të aktivizuar <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> dhe kjo <xliff:g id="PROFILE_NAME">%3$s</xliff:g> të mbahet pranë."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Nuk u gjet asnjë pajisje. Provo përsëri më vonë."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth-in"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth-in dhe Wi-Fi"</string>
- <string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
+ <string name="profile_name_watch" msgid="576290739483672360">"orë inteligjente"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Zgjidh një pajisje që do të menaxhohet nga &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Zgjidh një <xliff:g id="PROFILE_NAME">%1$s</xliff:g> për konfigurimin"</string>
<string name="single_device_title" msgid="4199861437545438606">"Po kërkon për një <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
@@ -45,7 +45,7 @@
<string name="title_sensor_device_streaming" msgid="2395553261097861497">"Të lejohet që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të transmetojë audion dhe veçoritë e sistemit mes <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> dhe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> do të ketë qasje në çdo gjë që luhet në pajisjen tënde <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.&lt;br/&gt;&lt;br/&gt;<xliff:g id="APP_NAME_2">%1$s</xliff:g> do të mund të transmetojë audion te <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> derisa të heqësh qasjen për këtë leje."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_NAME">%2$s</xliff:g> për të transmetuar audion dhe veçoritë e sistemit mes pajisjeve të tua"</string>
- <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
+ <string name="profile_name_generic" msgid="6851028682723034988">"pajisje"</string>
<string name="summary_generic" msgid="1761976003668044801">"Ky aplikacion do të mund të sinkronizojë informacione, si p.sh emrin e dikujt që po telefonon, mes telefonit tënd dhe pajisjes së zgjedhur."</string>
<string name="consent_yes" msgid="8344487259618762872">"Lejo"</string>
<string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index a86d1e1a5639..5f7e53dadbae 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -18,16 +18,16 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Менаџер придруженог уређаја"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Дозволите да апликација &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа уређају &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Уверите се да је за <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> укључен <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> и да у близини имате <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Уверите се да је на <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> укључен <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> и да у близини имате <xliff:g id="PROFILE_NAME">%3$s</xliff:g>."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Није пронађен ниједан уређај. Пробајте поново касније."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"WiFi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth и WiFi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Одаберите уређај којим ће управљати апликација &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> који желите да подесите"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Одаберите <xliff:g id="PROFILE_NAME">%1$s</xliff:g> који желите да подесите"</string>
<string name="single_device_title" msgid="4199861437545438606">"Тражи се <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="8134580124808507407">"Овој апликацији ће бити дозвољено да синхронизује податке, попут имена позиваоца, и приступа тим дозволама на уређају <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"Овој апликацији ће бити дозвољено да синхронизује податке, попут имена позиваоца, и приступа следећим дозволама на <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Желите ли да дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управља уређајем &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"уређај"</string>
<string name="summary_glasses" msgid="5469208629679579157">"Овој апликацији ће бити дозвољено да приступа овим дозволама на уређају <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index 779079092f50..a622ff4465bd 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="confirmation_title" msgid="2244241995958340998">"Vill du tillåta att appen &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får åtkomst till &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
- <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Se till att <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> har <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> aktiverat och håll <xliff:g id="PROFILE_NAME">%3$s</xliff:g> i närheten."</string>
+ <string name="message_discovery_soft_timeout" msgid="473346859407859161">"Se till att denna <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> har <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> aktiverat och håll din <xliff:g id="PROFILE_NAME">%3$s</xliff:g> i närheten."</string>
<string name="message_discovery_hard_timeout" msgid="677514663495711424">"Inga enheter hittades. Försök igen senare."</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"Wifi"</string>
@@ -26,7 +26,7 @@
<string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Välj en enhet för hantering av &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="chooser_title" msgid="2235819929238267637">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för konfigurering"</string>
- <string name="single_device_title" msgid="4199861437545438606">"Söker efter ett <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
+ <string name="single_device_title" msgid="4199861437545438606">"Söker efter en <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Appen får synkronisera information, till exempel namnet på någon som ringer, och får åtkomst till dessa behörigheter på din <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Tillåt att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hanterar &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"enhet"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index b39b58a39df7..f353b800cc3e 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -24,7 +24,7 @@
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"బ్లూటూత్, Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
- <string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ద్వారా మేనేజ్ చేయబడే పరికరాన్ని ఎంచుకోండి"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; మేనేజ్ చేయాల్సిన పరికరాన్ని ఎంచుకోండి"</string>
<string name="chooser_title" msgid="2235819929238267637">"సెటప్ చేయడానికి <xliff:g id="PROFILE_NAME">%1$s</xliff:g>‌ను ఎంచుకోండి"</string>
<string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> కోసం స్కాన్ చేస్తోంది"</string>
<string name="summary_watch" msgid="8134580124808507407">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని సింక్ చేయడానికి, మీ <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>‌లో ఈ అనుమతులను యాక్సెస్ చేయడానికి ఈ యాప్ అనుమతించబడుతుంది"</string>
@@ -46,7 +46,7 @@
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> మీ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>‌లో ప్లే చేయబడిన దేనికైనా యాక్సెస్ కలిగి ఉంటుంది.&lt;br/&gt;&lt;br/&gt;మీరు ఈ అనుమతికి యాక్సెస్‌ను తీసివేసే వరకు <xliff:g id="APP_NAME_2">%1$s</xliff:g> ఆడియోను <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>‌కు స్ట్రీమ్ చేయగలదు."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"మీ పరికరాల మధ్య ఆడియో, సిస్టమ్ ఫీచర్‌లను స్ట్రీమ్ చేయడానికి <xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరపున <xliff:g id="APP_NAME">%1$s</xliff:g> యాప్ అనుమతిని రిక్వెస్ట్ చేస్తోంది."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
- <string name="summary_generic" msgid="1761976003668044801">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని ఈ యాప్ మీ ఫోన్ కు, ఎంచుకున్న పరికరానికీ మధ్య సింక్ చేయగలుగుతుంది"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"ఈ యాప్, కాల్ చేస్తున్న వారి పేరు లాంటి సమాచారాన్ని మీ ఫోన్‌కు, సెలెక్ట్ అయిన పరికరానికి మధ్య సింక్ చేస్తుంది."</string>
<string name="consent_yes" msgid="8344487259618762872">"అనుమతించండి"</string>
<string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string>
<string name="consent_cancel" msgid="5655005528379285841">"రద్దు చేయండి"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index 9150a48fafdd..8d5470c68c3f 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -25,7 +25,7 @@
<string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth at Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
<string name="chooser_title_non_profile" msgid="6035023914517087400">"Pumili ng device na papamahalaan ng &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
- <string name="chooser_title" msgid="2235819929238267637">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para mag-set up"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para i-set up"</string>
<string name="single_device_title" msgid="4199861437545438606">"Hinahanap ang <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"Papayagan ang app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, at ma-access ang mga pahintulot na ito sa iyong <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na pamahalaan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
@@ -46,7 +46,7 @@
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Magkakaroon ng access ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> sa anumang pine-play sa iyong <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.&lt;br/&gt;&lt;br/&gt;Makakapag-stream ang <xliff:g id="APP_NAME_2">%1$s</xliff:g> ng audio sa <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hanggang sa alisin mo ang access sa pahintulot na ito."</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Humihingi ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng pahintulot para sa <xliff:g id="DEVICE_NAME">%2$s</xliff:g> na mag-stream ng audio at mga feature ng system sa pagitan ng iyong mga device."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
- <string name="summary_generic" msgid="1761976003668044801">"Magagawa ng app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, sa pagitan ng iyong telepono at ng napiling device"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"Magagawa ng app na ito na mag-sync ng impormasyon, tulad ng pangalan ng taong tumatawag, sa pagitan ng telepono mo at ng napiling device"</string>
<string name="consent_yes" msgid="8344487259618762872">"Payagan"</string>
<string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string>
<string name="consent_cancel" msgid="5655005528379285841">"Kanselahin"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index e502a792d23b..f517742973ff 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -24,7 +24,7 @@
<string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"‏بلوٹوتھ اور Wi-Fi"</string>
<string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
- <string name="chooser_title_non_profile" msgid="6035023914517087400">"‏‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‎ کے ذریعے منتخب کیے جانے کیلئے آلہ منتخب کریں"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"‏کوئی آلہ منتخب کریں جس کا نظم و نسق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کرے"</string>
<string name="chooser_title" msgid="2235819929238267637">"سیٹ اپ کرنے کے لیے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کا انتخاب کریں"</string>
<string name="single_device_title" msgid="4199861437545438606">"‫<xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو تلاش کیا جا رہا ہے"</string>
<string name="summary_watch" msgid="8134580124808507407">"اس ایپ کو آپ کے <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> پر کسی کال کرنے والے کے نام جیسی معلومات کی مطابقت پذیری کرنے اور ان اجازتوں تک رسائی کی اجازت ہوگی"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 4360092564ea..ccc046b3c3f7 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -17,15 +17,15 @@
<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="4470785958457506021">"配套设备管理器"</string>
- <string name="confirmation_title" msgid="2244241995958340998">"允许应用&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;访问&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
+ <string name="confirmation_title" msgid="2244241995958340998">"要允许“&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;”应用访问“&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;”吗?"</string>
<string name="message_discovery_soft_timeout" msgid="473346859407859161">"请确保此<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>已开启<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g>,并将<xliff:g id="PROFILE_NAME">%3$s</xliff:g>放在附近。"</string>
- <string name="message_discovery_hard_timeout" msgid="677514663495711424">"找不到设备,请稍后重试。"</string>
+ <string name="message_discovery_hard_timeout" msgid="677514663495711424">"未找到设备,请稍后重试。"</string>
<string name="discovery_bluetooth" msgid="5693557668470016164">"蓝牙"</string>
<string name="discovery_wifi" msgid="1551782459721758773">"WLAN"</string>
<string name="discovery_mixed" msgid="7071466134150760127">"蓝牙和 WLAN"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
- <string name="chooser_title_non_profile" msgid="6035023914517087400">"选择要由&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;管理的设备"</string>
- <string name="chooser_title" msgid="2235819929238267637">"选择 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 进行设置"</string>
+ <string name="chooser_title_non_profile" msgid="6035023914517087400">"选择要由“&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;”管理的设备"</string>
+ <string name="chooser_title" msgid="2235819929238267637">"选择要设置的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="single_device_title" msgid="4199861437545438606">"寻找<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" msgid="8134580124808507407">"该应用将能同步信息(例如来电者的姓名),并能获得您<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的以下权限"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;管理&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 2bfcaf296420..a96e43fb135e 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -27,7 +27,7 @@
<string name="chooser_title_non_profile" msgid="6035023914517087400">"選擇要讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理的裝置"</string>
<string name="chooser_title" msgid="2235819929238267637">"選擇要設定的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="single_device_title" msgid="4199861437545438606">"尋找<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <string name="summary_watch" msgid="8134580124808507407">"這個應用程式將可同步處理資訊 (例如來電者名稱) 及取得<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的這些權限"</string>
+ <string name="summary_watch" msgid="8134580124808507407">"這個應用程式可同步處理資訊 (例如來電者名稱) 和取得<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的這些權限"</string>
<string name="confirmation_title_glasses" msgid="8288346850537727333">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;嗎?"</string>
<string name="profile_name_glasses" msgid="3506504967216601277">"裝置"</string>
<string name="summary_glasses" msgid="5469208629679579157">"這個應用程式將可取得<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>上的這些權限"</string>
@@ -46,7 +46,7 @@
<string name="summary_sensor_device_streaming" msgid="3413105061195145547">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將可存取「<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>」播放的所有內容。&lt;br/&gt;&lt;br/&gt;「<xliff:g id="APP_NAME_2">%1$s</xliff:g>」可將音訊串流傳輸到「<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>」,直到你移除這個權限為止。"</string>
<string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」要求必要權限,以便在裝置間串流傳輸音訊和系統功能。"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
- <string name="summary_generic" msgid="1761976003668044801">"這個應用程式將可在手機和指定裝置間同步資訊,例如來電者名稱"</string>
+ <string name="summary_generic" msgid="1761976003668044801">"這個應用程式可在手機和指定裝置間同步資訊,例如來電者名稱"</string>
<string name="consent_yes" msgid="8344487259618762872">"允許"</string>
<string name="consent_no" msgid="2640796915611404382">"不允許"</string>
<string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml
index 651488776c22..86dd090dc7c1 100644
--- a/packages/CredentialManager/res/values-pl/strings.xml
+++ b/packages/CredentialManager/res/values-pl/strings.xml
@@ -42,7 +42,7 @@
<string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Utworzyć klucz dostępu do logowania w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="4481366993598649224">"Zapisać hasło do logowania w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Zapisać dane używane do logowania w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
- <string name="passkey" msgid="632353688396759522">"klucz"</string>
+ <string name="passkey" msgid="632353688396759522">"klucz dostępu"</string>
<string name="password" msgid="6738570945182936667">"hasło"</string>
<string name="passkeys" msgid="5733880786866559847">"klucze dostępu"</string>
<string name="passwords" msgid="5419394230391253816">"hasła"</string>
@@ -61,7 +61,7 @@
<string name="more_options_usage_passwords" msgid="1632047277723187813">"Hasła: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_passkeys" msgid="5390320437243042237">"Klucze dostępu: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
<string name="more_options_usage_credentials" msgid="1785697001787193984">"Dane logowania: <xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g>"</string>
- <string name="passkey_before_subtitle" msgid="2448119456208647444">"Klucz"</string>
+ <string name="passkey_before_subtitle" msgid="2448119456208647444">"Klucz dostępu"</string>
<string name="another_device" msgid="5147276802037801217">"Inne urządzenie"</string>
<string name="other_password_manager" msgid="565790221427004141">"Inne menedżery haseł"</string>
<string name="close_sheet" msgid="1393792015338908262">"Zamknij arkusz"</string>
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index a3b06e8c71fc..1af3bc898306 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -23,6 +23,7 @@ import android.app.backup.BackupAnnotations;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupManagerMonitor;
+import android.app.backup.BackupRestoreEventLogger;
import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
import android.app.backup.BackupTransport;
import android.app.backup.RestoreDescription;
@@ -52,7 +53,6 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -924,21 +924,9 @@ public class LocalTransport extends BackupTransport {
BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS,
DataTypeResult.class);
for (DataTypeResult result : results) {
- Log.i(TAG, "\tdataType: " + result.getDataType());
- Log.i(TAG, "\tsuccessCount: " + result.getSuccessCount());
- Log.i(TAG, "\tfailCount: " + result.getFailCount());
- Log.i(TAG, "\tmetadataHash: " + Arrays.toString(result.getMetadataHash()));
-
- if (!result.getErrors().isEmpty()) {
- Log.i(TAG, "\terrors {");
- for (String error : result.getErrors().keySet()) {
- Log.i(TAG, "\t\t" + error + ": " + result.getErrors().get(error));
- }
- Log.i(TAG, "\t}");
- }
-
- Log.i(TAG, "}");
+ Log.i(TAG, "\t" + BackupRestoreEventLogger.toString(result));
}
+ Log.i(TAG, "}");
}
}
}
diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml
index 98eae5abe9a1..bbcf90065168 100644
--- a/packages/PackageInstaller/res/values-my/strings.xml
+++ b/packages/PackageInstaller/res/values-my/strings.xml
@@ -58,7 +58,7 @@
<string name="uninstall_application_title" msgid="4045420072401428123">"အက်ပ်ကို ဖယ်ရှားရန်"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"အပ်ဒိတ်ကို ဖယ်ရှားရန်"</string>
<string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> သည် အောက်ပါအက်ပ်၏ တစ်စိတ်တစ်ဒေသဖြစ်သည်−"</string>
- <string name="uninstall_application_text" msgid="3816830743706143980">"ဤအက်ပ်ကို ဖယ်ရှားလိုပါသလား။"</string>
+ <string name="uninstall_application_text" msgid="3816830743706143980">"ဤအက်ပ်ကို ဖြုတ်လိုပါသလား။"</string>
<string name="archive_application_text" msgid="8482325710714386348">"သင့်ကိုယ်ရေးအချက်အလက်ကို သိမ်းပါမည်"</string>
<string name="archive_application_text_all_users" msgid="3151229641681672580">"ဤအက်ပ်ကို အသုံးပြုသူအားလုံးအတွက် သိမ်းမလား။ သင့်ကိုယ်ရေးအချက်အလက်ကို သိမ်းပါမည်"</string>
<string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ဤအက်ပ်ကို သင့်အလုပ်ပရိုဖိုင်တွင် သိမ်းမလား။ သင့်ကိုယ်ရေးအချက်အလက်ကို သိမ်းပါမည်"</string>
diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
index 332517a775f4..f356bb462565 100644
--- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
@@ -58,7 +58,7 @@
<string name="uninstall_application_title" msgid="4045420072401428123">"Desinstalar app"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar atualização"</string>
<string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> é parte do seguinte app:"</string>
- <string name="uninstall_application_text" msgid="3816830743706143980">"Você quer desinstalar este app?"</string>
+ <string name="uninstall_application_text" msgid="3816830743706143980">"Você quer desinstalar esse app?"</string>
<string name="archive_application_text" msgid="8482325710714386348">"Seus dados pessoais serão salvos"</string>
<string name="archive_application_text_all_users" msgid="3151229641681672580">"Arquivar esse app para todos os usuários? Seus dados pessoais serão salvos"</string>
<string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Arquivar esse app no seu perfil de trabalho? Seus dados pessoais serão salvos"</string>
diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml
index 332517a775f4..f356bb462565 100644
--- a/packages/PackageInstaller/res/values-pt/strings.xml
+++ b/packages/PackageInstaller/res/values-pt/strings.xml
@@ -58,7 +58,7 @@
<string name="uninstall_application_title" msgid="4045420072401428123">"Desinstalar app"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar atualização"</string>
<string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> é parte do seguinte app:"</string>
- <string name="uninstall_application_text" msgid="3816830743706143980">"Você quer desinstalar este app?"</string>
+ <string name="uninstall_application_text" msgid="3816830743706143980">"Você quer desinstalar esse app?"</string>
<string name="archive_application_text" msgid="8482325710714386348">"Seus dados pessoais serão salvos"</string>
<string name="archive_application_text_all_users" msgid="3151229641681672580">"Arquivar esse app para todos os usuários? Seus dados pessoais serão salvos"</string>
<string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Arquivar esse app no seu perfil de trabalho? Seus dados pessoais serão salvos"</string>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index b56b944955d7..af8e856a5ad6 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -35,5 +35,6 @@ android_library {
"com.android.extservices",
"com.android.permission",
"com.android.healthfitness",
+ "com.android.mediaprovider",
],
}
diff --git a/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml b/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml
index 7adcbf6c6601..cacd2740818c 100644
--- a/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml
+++ b/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml
@@ -17,6 +17,7 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/entity_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -38,7 +39,9 @@
android:id="@+id/collapsable_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center"/>
+ android:gravity="center"
+ android:minLines="1"
+ app:isCollapsable="true"/>
</LinearLayout>
diff --git a/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt b/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
index f9931cf3238d..9d037e91a86f 100644
--- a/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
+++ b/packages/SettingsLib/IntroPreference/src/com/android/settingslib/widget/IntroPreference.kt
@@ -33,8 +33,8 @@ class IntroPreference @JvmOverloads constructor(
defStyleRes: Int = 0
) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin {
- private var isCollapsable: Boolean = false
- private var minLines: Int = 2
+ private var isCollapsable: Boolean = true
+ private var minLines: Int = DEFAULT_MIN_LINES
private var hyperlinkListener: View.OnClickListener? = null
private var learnMoreListener: View.OnClickListener? = null
private var learnMoreText: CharSequence? = null
@@ -42,22 +42,6 @@ class IntroPreference @JvmOverloads constructor(
init {
layoutResource = R.layout.settingslib_expressive_preference_intro
isSelectable = false
-
- initAttributes(context, attrs, defStyleAttr)
- }
-
- private fun initAttributes(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {
- context.obtainStyledAttributes(
- attrs,
- COLLAPSABLE_TEXT_VIEW_ATTRS, defStyleAttr, 0
- ).apply {
- isCollapsable = getBoolean(IS_COLLAPSABLE, false)
- minLines = getInt(
- MIN_LINES,
- if (isCollapsable) DEFAULT_MIN_LINES else DEFAULT_MAX_LINES
- ).coerceIn(1, DEFAULT_MAX_LINES)
- recycle()
- }
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
@@ -139,13 +123,6 @@ class IntroPreference @JvmOverloads constructor(
companion object {
private const val DEFAULT_MAX_LINES = 10
- private const val DEFAULT_MIN_LINES = 2
-
- private val COLLAPSABLE_TEXT_VIEW_ATTRS =
- com.android.settingslib.widget.theme.R.styleable.CollapsableTextView
- private val MIN_LINES =
- com.android.settingslib.widget.theme.R.styleable.CollapsableTextView_android_minLines
- private val IS_COLLAPSABLE =
- com.android.settingslib.widget.theme.R.styleable.CollapsableTextView_isCollapsable
+ private const val DEFAULT_MIN_LINES = 1
}
-} \ No newline at end of file
+}
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt
index dbac17d4e8b8..44c93c77e33b 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt
@@ -74,8 +74,14 @@ interface BooleanValuePreferenceBinding : PreferenceBinding {
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
super.bind(preference, metadata)
(preference as TwoStatePreference).apply {
+ // MUST suppress persistent when initializing the checked state:
+ // 1. default value is written to datastore if not set (b/396260949)
+ // 2. avoid redundant read to the datastore
+ val suppressPersistent = isPersistent
+ if (suppressPersistent) isPersistent = false
// "false" is kind of placeholder, metadata datastore should provide the default value
isChecked = preferenceDataStore!!.getBoolean(key, false)
+ if (suppressPersistent) isPersistent = true
}
}
}
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/CollapsableTextView.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/CollapsableTextView.kt
index 7eb9840e3e98..976711bdc5f3 100644
--- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/CollapsableTextView.kt
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/CollapsableTextView.kt
@@ -40,7 +40,7 @@ class CollapsableTextView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
- private var isCollapsable: Boolean = false
+ private var isCollapsable: Boolean = DEFAULT_COLLAPSABLE
private var isCollapsed: Boolean = false
private var minLines: Int = DEFAULT_MIN_LINES
@@ -78,24 +78,38 @@ class CollapsableTextView @JvmOverloads constructor(
private fun initAttributes(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {
context.obtainStyledAttributes(
- attrs, Attrs, defStyleAttr, 0
+ attrs, R.styleable.CollapsableTextView, defStyleAttr, 0
).apply {
- val gravity = getInt(GravityAttr, Gravity.START)
+ val gravity = getInt(gravityAttr, Gravity.START)
when (gravity) {
Gravity.CENTER_VERTICAL, Gravity.CENTER, Gravity.CENTER_HORIZONTAL -> {
centerHorizontally(titleTextView)
centerHorizontally(collapseButton)
}
}
+ isCollapsable = getBoolean(isCollapsableAttr, DEFAULT_COLLAPSABLE)
+ minLines = getInt(minLinesAttr, DEFAULT_MIN_LINES)
recycle()
}
}
private fun centerHorizontally(view: View) {
- (view.layoutParams as LayoutParams).apply {
- startToStart = LayoutParams.PARENT_ID
- endToEnd = LayoutParams.PARENT_ID
- horizontalBias = 0.5f
+ when (view) {
+ is MaterialButton -> {
+ (view.layoutParams as LayoutParams).apply {
+ startToStart = LayoutParams.PARENT_ID
+ endToEnd = LayoutParams.PARENT_ID
+ }
+ }
+ is TextView -> {
+ view.gravity = Gravity.CENTER
+ }
+ else -> {
+ (view.layoutParams as LayoutParams).apply {
+ startToStart = LayoutParams.PARENT_ID
+ endToEnd = LayoutParams.PARENT_ID
+ }
+ }
}
}
@@ -113,6 +127,8 @@ class CollapsableTextView @JvmOverloads constructor(
*/
fun setCollapsable(collapsable: Boolean) {
isCollapsable = collapsable
+ // Make is collapsed when it's collapsable
+ if (isCollapsable) isCollapsed = true
updateView()
}
@@ -120,8 +136,8 @@ class CollapsableTextView @JvmOverloads constructor(
* Sets the minimum number of lines to display when collapsed.
* @param lines The minimum number of lines.
*/
- fun setMinLines(line: Int) {
- minLines = line.coerceIn(1, DEFAULT_MAX_LINES)
+ fun setMinLines(lines: Int) {
+ minLines = lines.coerceIn(1, DEFAULT_MAX_LINES)
updateView()
}
@@ -198,7 +214,7 @@ class CollapsableTextView @JvmOverloads constructor(
}
learnMoreSpan = LearnMoreSpan(clickListener = learnMoreListener!!)
spannableLearnMoreText.setSpan(learnMoreSpan, 0, learnMoreText!!.length, 0)
- learnMoreTextView.setText(spannableLearnMoreText)
+ learnMoreTextView.text = spannableLearnMoreText
learnMoreTextView.visibility = VISIBLE
isLearnMoreEnabled = true
}
@@ -211,6 +227,8 @@ class CollapsableTextView @JvmOverloads constructor(
icon = collapseButtonResources.expandIcon
}
titleTextView.maxLines = minLines
+ titleTextView.ellipsize = null
+ titleTextView.scrollBarSize = 0
}
else -> {
@@ -219,6 +237,7 @@ class CollapsableTextView @JvmOverloads constructor(
icon = collapseButtonResources.collapseIcon
}
titleTextView.maxLines = DEFAULT_MAX_LINES
+ titleTextView.ellipsize = TextUtils.TruncateAt.END
}
}
collapseButton.visibility = if (isCollapsable) VISIBLE else GONE
@@ -235,17 +254,19 @@ class CollapsableTextView @JvmOverloads constructor(
companion object {
private const val DEFAULT_MAX_LINES = 10
private const val DEFAULT_MIN_LINES = 2
+ private const val DEFAULT_COLLAPSABLE = true
private const val LINK_BEGIN_MARKER = "LINK_BEGIN"
private const val LINK_END_MARKER = "LINK_END"
- private val Attrs = R.styleable.CollapsableTextView
- private val GravityAttr = R.styleable.CollapsableTextView_android_gravity
+ private val gravityAttr = R.styleable.CollapsableTextView_android_gravity
+ private val minLinesAttr = R.styleable.CollapsableTextView_android_minLines
+ private val isCollapsableAttr = R.styleable.CollapsableTextView_isCollapsable
}
}
internal class LearnMoreSpan(
- val url: String = "",
+ url: String = "",
val clickListener: View.OnClickListener) : URLSpan(url) {
override fun onClick(widget: View) {
clickListener.onClick(widget)
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt
index bfaeb42d5a31..8d12f01e24ed 100644
--- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt
@@ -17,7 +17,9 @@
package com.android.settingslib.widget
import android.os.Bundle
+import android.view.LayoutInflater;
import android.view.View
+import android.view.ViewGroup;
import androidx.annotation.CallSuper
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
@@ -27,6 +29,15 @@ import androidx.recyclerview.widget.RecyclerView
abstract class SettingsBasePreferenceFragment : PreferenceFragmentCompat() {
@CallSuper
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ return super.onCreateView(inflater, container, savedInstanceState)
+ }
+
+ @CallSuper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (SettingsThemeHelper.isExpressiveTheme(requireContext())) {
diff --git a/packages/SettingsLib/SettingsTransition/Android.bp b/packages/SettingsLib/SettingsTransition/Android.bp
index e04af6c1ab11..6b9cbfa8ece7 100644
--- a/packages/SettingsLib/SettingsTransition/Android.bp
+++ b/packages/SettingsLib/SettingsTransition/Android.bp
@@ -30,5 +30,6 @@ android_library {
"com.android.extservices",
"com.android.permission",
"com.android.healthfitness",
+ "com.android.mediaprovider",
],
}
diff --git a/packages/SettingsLib/TopIntroPreference/Android.bp b/packages/SettingsLib/TopIntroPreference/Android.bp
index 76e36dc5ff7d..bf26264a4f0e 100644
--- a/packages/SettingsLib/TopIntroPreference/Android.bp
+++ b/packages/SettingsLib/TopIntroPreference/Android.bp
@@ -32,5 +32,6 @@ android_library {
"com.android.cellbroadcast",
"com.android.devicelock",
"com.android.healthfitness",
+ "com.android.mediaprovider",
],
}
diff --git a/packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml
new file mode 100644
index 000000000000..bd2fad2fedc0
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="12.88dp"
+ android:viewportWidth="13.53"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M3.738,10.252C3.468,10.252 3.234,10.154 3.038,9.958C2.847,9.757 2.751,9.522 2.751,9.251L2.751,2.587L1.372,3.497C1.167,3.628 0.943,3.672 0.7,3.63C0.462,3.588 0.276,3.467 0.14,3.266C0.01,3.065 -0.032,2.844 0.014,2.601C0.066,2.358 0.192,2.172 0.392,2.041L3.185,0.2C3.265,0.149 3.344,0.104 3.423,0.067C3.507,0.025 3.619,0.004 3.759,0.004C4.03,0.004 4.259,0.102 4.445,0.298C4.637,0.494 4.732,0.734 4.732,1.019L4.732,9.251C4.732,9.522 4.634,9.757 4.438,9.958C4.242,10.154 4.009,10.252 3.738,10.252ZM12.582,10.245C12.391,10.245 12.218,10.194 12.064,10.091C11.915,9.984 11.796,9.848 11.707,9.685L9.803,6.038L9.593,5.961L7.332,1.411C7.136,1.084 7.127,0.769 7.304,0.466C7.482,0.163 7.755,0.011 8.123,0.011C8.301,0.011 8.466,0.065 8.62,0.172C8.779,0.279 8.903,0.415 8.991,0.578L10.783,4.015L11.014,4.05L13.373,8.796C13.569,9.132 13.581,9.459 13.408,9.776C13.236,10.089 12.96,10.245 12.582,10.245ZM7.92,10.238C7.57,10.238 7.309,10.089 7.136,9.79C6.968,9.491 6.978,9.186 7.164,8.873L9.621,4.008L9.817,4.008L11.63,0.557C11.719,0.398 11.836,0.27 11.98,0.172C12.125,0.069 12.288,0.018 12.47,0.018C12.816,0.018 13.075,0.163 13.247,0.452C13.42,0.741 13.411,1.047 13.219,1.369L10.909,5.982L10.762,5.989L8.781,9.713C8.697,9.867 8.578,9.993 8.424,10.091C8.27,10.189 8.102,10.238 7.92,10.238Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml
new file mode 100644
index 000000000000..8e632e69a56e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="12.21dp"
+ android:viewportWidth="14.51"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M2.827,10.416C2.225,10.416 1.726,10.311 1.329,10.101C0.937,9.891 0.629,9.606 0.405,9.247C0.181,8.888 0.051,8.58 0.013,8.323C-0.019,8.066 0.023,7.849 0.139,7.672C0.256,7.49 0.415,7.371 0.615,7.315C0.816,7.254 1.003,7.259 1.175,7.329C1.353,7.394 1.481,7.495 1.56,7.63C1.644,7.765 1.733,7.922 1.826,8.099C1.92,8.272 2.041,8.416 2.19,8.533C2.34,8.65 2.533,8.708 2.771,8.708C3.089,8.708 3.343,8.615 3.534,8.428C3.726,8.237 3.821,7.959 3.821,7.595L3.821,6.888C3.821,6.529 3.726,6.256 3.534,6.069C3.348,5.882 3.077,5.789 2.722,5.789L2.456,5.789C2.251,5.789 2.071,5.714 1.917,5.565C1.768,5.416 1.693,5.236 1.693,5.026C1.693,4.816 1.768,4.636 1.917,4.487C2.067,4.338 2.244,4.263 2.449,4.263L2.666,4.263C2.984,4.263 3.222,4.177 3.38,4.004C3.544,3.831 3.625,3.558 3.625,3.185L3.625,2.618C3.625,2.315 3.544,2.084 3.38,1.925C3.217,1.766 2.998,1.687 2.722,1.687C2.531,1.687 2.37,1.729 2.239,1.813C2.109,1.892 1.999,2.004 1.91,2.149C1.822,2.294 1.738,2.427 1.658,2.548C1.579,2.665 1.453,2.756 1.28,2.821C1.108,2.882 0.926,2.882 0.734,2.821C0.543,2.756 0.391,2.632 0.279,2.45C0.172,2.268 0.142,2.049 0.188,1.792C0.24,1.531 0.384,1.248 0.622,0.945C0.86,0.642 1.159,0.408 1.518,0.245C1.882,0.082 2.326,0 2.848,0C3.67,0 4.323,0.215 4.808,0.644C5.294,1.069 5.536,1.636 5.536,2.345L5.536,2.8C5.536,3.332 5.417,3.768 5.179,4.109C4.941,4.445 4.598,4.69 4.15,4.844L4.15,4.9C4.678,5.017 5.086,5.259 5.375,5.628C5.669,5.992 5.816,6.484 5.816,7.105L5.816,7.679C5.816,8.514 5.55,9.179 5.018,9.674C4.491,10.169 3.761,10.416 2.827,10.416ZM10.943,10.416C9.819,10.411 8.92,10.031 8.248,9.275C7.581,8.514 7.247,7.406 7.247,5.95L7.247,4.417C7.247,2.975 7.588,1.878 8.269,1.127C8.951,0.371 9.863,-0.005 11.006,0C11.52,0 11.954,0.075 12.308,0.224C12.668,0.369 12.973,0.576 13.225,0.847C13.482,1.113 13.659,1.374 13.757,1.631C13.855,1.883 13.862,2.121 13.778,2.345C13.694,2.569 13.55,2.732 13.344,2.835C13.144,2.938 12.948,2.968 12.756,2.926C12.565,2.884 12.416,2.802 12.308,2.681C12.201,2.555 12.091,2.422 11.979,2.282C11.867,2.142 11.727,2.032 11.559,1.953C11.391,1.869 11.191,1.827 10.957,1.827C10.439,1.822 10.024,2.011 9.711,2.394C9.403,2.777 9.249,3.358 9.249,4.137L9.249,6.293C9.249,7.063 9.408,7.644 9.725,8.036C10.047,8.428 10.467,8.624 10.985,8.624C11.489,8.624 11.884,8.477 12.168,8.183C12.453,7.889 12.607,7.474 12.63,6.937L12.63,6.265L11.657,6.265C11.452,6.265 11.275,6.188 11.125,6.034C10.976,5.875 10.901,5.689 10.901,5.474C10.901,5.255 10.978,5.068 11.132,4.914C11.291,4.755 11.48,4.676 11.699,4.676L13.666,4.676C13.9,4.676 14.098,4.755 14.261,4.914C14.425,5.073 14.509,5.269 14.513,5.502L14.513,6.538C14.513,7.77 14.191,8.724 13.547,9.401C12.908,10.078 12.04,10.416 10.943,10.416Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml
new file mode 100644
index 000000000000..bba359e8b238
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="34dp"
+ android:height="14.07dp"
+ android:viewportWidth="27.29"
+ android:viewportHeight="11.29">
+ <path
+ android:pathData="M4.552,11.195C4.286,11.195 4.058,11.099 3.866,10.908C3.68,10.717 3.586,10.488 3.586,10.222L3.586,8.171L3.74,7.891L3.74,2.823L4.72,3.53L3.712,3.53L1.808,7.366L4.37,7.366L4.797,7.275L5.777,7.275C6.015,7.275 6.218,7.359 6.386,7.527C6.554,7.695 6.638,7.898 6.638,8.136C6.638,8.369 6.554,8.57 6.386,8.738C6.218,8.906 6.015,8.99 5.777,8.99L1.192,8.99C0.856,8.99 0.572,8.88 0.338,8.661C0.11,8.442 -0.005,8.169 -0.005,7.842C-0.005,7.683 0.016,7.569 0.058,7.499C0.1,7.424 0.142,7.35 0.184,7.275L3.124,1.633C3.222,1.446 3.374,1.283 3.579,1.143C3.789,1.003 4.013,0.933 4.251,0.933C4.606,0.933 4.905,1.061 5.147,1.318C5.39,1.57 5.511,1.876 5.511,2.235L5.511,10.222C5.511,10.488 5.416,10.717 5.224,10.908C5.038,11.099 4.814,11.195 4.552,11.195ZM11.303,11.286C10.179,11.281 9.28,10.901 8.608,10.145C7.941,9.384 7.607,8.276 7.607,6.82L7.607,5.287C7.607,3.845 7.948,2.748 8.629,1.997C9.311,1.241 10.223,0.865 11.366,0.87C11.88,0.87 12.314,0.945 12.668,1.094C13.028,1.239 13.333,1.446 13.585,1.717C13.842,1.983 14.019,2.244 14.117,2.501C14.215,2.753 14.222,2.991 14.138,3.215C14.054,3.439 13.91,3.602 13.704,3.705C13.504,3.808 13.308,3.838 13.116,3.796C12.925,3.754 12.776,3.672 12.668,3.551C12.561,3.425 12.451,3.292 12.339,3.152C12.227,3.012 12.087,2.902 11.919,2.823C11.751,2.739 11.551,2.697 11.317,2.697C10.799,2.692 10.384,2.881 10.071,3.264C9.763,3.647 9.609,4.228 9.609,5.007L9.609,7.163C9.609,7.933 9.768,8.514 10.085,8.906C10.407,9.298 10.827,9.494 11.345,9.494C11.849,9.494 12.244,9.347 12.528,9.053C12.813,8.759 12.967,8.344 12.99,7.807L12.99,7.135L12.017,7.135C11.812,7.135 11.635,7.058 11.485,6.904C11.336,6.745 11.261,6.559 11.261,6.344C11.261,6.125 11.338,5.938 11.492,5.784C11.651,5.625 11.84,5.546 12.059,5.546L14.026,5.546C14.26,5.546 14.458,5.625 14.621,5.784C14.785,5.943 14.869,6.139 14.873,6.372L14.873,7.408C14.873,8.64 14.551,9.594 13.907,10.271C13.268,10.948 12.4,11.286 11.303,11.286ZM16.641,6.09C16.434,6.09 16.256,6.016 16.108,5.867C15.962,5.719 15.89,5.543 15.89,5.338L15.89,0.689C15.89,0.501 15.957,0.34 16.091,0.206C16.226,0.069 16.385,0 16.57,0C16.758,0 16.919,0.069 17.053,0.206C17.187,0.34 17.255,0.501 17.255,0.689L17.255,4.83L18.54,4.83C18.713,4.83 18.863,4.892 18.989,5.015C19.115,5.138 19.178,5.286 19.178,5.46C19.178,5.631 19.115,5.779 18.989,5.905C18.863,6.028 18.713,6.09 18.54,6.09L16.641,6.09ZM20.979,6.166C20.792,6.166 20.63,6.098 20.496,5.964C20.365,5.827 20.299,5.664 20.299,5.477L20.299,0.731L21.664,0.731L21.664,5.477C21.664,5.664 21.597,5.827 21.462,5.964C21.328,6.098 21.167,6.166 20.979,6.166ZM19.648,1.331C19.474,1.331 19.324,1.27 19.198,1.147C19.075,1.023 19.014,0.876 19.014,0.706C19.014,0.532 19.075,0.384 19.198,0.26C19.324,0.137 19.474,0.076 19.648,0.076L22.306,0.076C22.48,0.076 22.628,0.137 22.751,0.26C22.877,0.384 22.941,0.532 22.941,0.706C22.941,0.876 22.877,1.023 22.751,1.147C22.628,1.27 22.48,1.331 22.306,1.331L19.648,1.331ZM24.553,6.09C24.346,6.09 24.168,6.016 24.019,5.867C23.874,5.719 23.801,5.543 23.801,5.338L23.801,0.823C23.801,0.619 23.874,0.444 24.019,0.298C24.168,0.15 24.346,0.076 24.553,0.076L26.59,0.076C26.763,0.076 26.912,0.137 27.035,0.26C27.161,0.384 27.224,0.531 27.224,0.701C27.224,0.872 27.161,1.019 27.035,1.142C26.912,1.266 26.763,1.327 26.59,1.327L25.158,1.327L25.158,4.838L26.657,4.838C26.831,4.838 26.979,4.9 27.102,5.023C27.225,5.146 27.287,5.293 27.287,5.464C27.287,5.635 27.225,5.782 27.102,5.905C26.979,6.028 26.831,6.09 26.657,6.09L24.553,6.09ZM24.637,3.595L24.637,2.444L26.3,2.444C26.46,2.444 26.595,2.5 26.707,2.612C26.822,2.724 26.88,2.86 26.88,3.02C26.88,3.177 26.822,3.312 26.707,3.427C26.595,3.539 26.46,3.595 26.3,3.595L24.637,3.595Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..cb6fd50a07ea
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="34dp"
+ android:height="11.93dp"
+ android:viewportWidth="32.18"
+ android:viewportHeight="11.29">
+ <path
+ android:pathData="M4.552,11.195C4.286,11.195 4.058,11.099 3.866,10.908C3.68,10.717 3.586,10.488 3.586,10.222L3.586,8.171L3.74,7.891L3.74,2.823L4.72,3.53L3.712,3.53L1.808,7.366L4.37,7.366L4.797,7.275L5.777,7.275C6.015,7.275 6.218,7.359 6.386,7.527C6.554,7.695 6.638,7.898 6.638,8.136C6.638,8.369 6.554,8.57 6.386,8.738C6.218,8.906 6.015,8.99 5.777,8.99L1.192,8.99C0.856,8.99 0.572,8.88 0.338,8.661C0.11,8.442 -0.005,8.169 -0.005,7.842C-0.005,7.683 0.016,7.569 0.058,7.499C0.1,7.424 0.142,7.35 0.184,7.275L3.124,1.633C3.222,1.446 3.374,1.283 3.579,1.143C3.789,1.003 4.013,0.933 4.251,0.933C4.606,0.933 4.905,1.061 5.147,1.318C5.39,1.57 5.511,1.876 5.511,2.235L5.511,10.222C5.511,10.488 5.416,10.717 5.224,10.908C5.038,11.099 4.814,11.195 4.552,11.195ZM11.303,11.286C10.179,11.281 9.28,10.901 8.608,10.145C7.941,9.384 7.607,8.276 7.607,6.82L7.607,5.287C7.607,3.845 7.948,2.748 8.629,1.997C9.311,1.241 10.223,0.865 11.366,0.87C11.88,0.87 12.314,0.945 12.668,1.094C13.028,1.239 13.333,1.446 13.585,1.717C13.842,1.983 14.019,2.244 14.117,2.501C14.215,2.753 14.222,2.991 14.138,3.215C14.054,3.439 13.91,3.602 13.704,3.705C13.504,3.808 13.308,3.838 13.116,3.796C12.925,3.754 12.776,3.672 12.668,3.551C12.561,3.425 12.451,3.292 12.339,3.152C12.227,3.012 12.087,2.902 11.919,2.823C11.751,2.739 11.551,2.697 11.317,2.697C10.799,2.692 10.384,2.881 10.071,3.264C9.763,3.647 9.609,4.228 9.609,5.007L9.609,7.163C9.609,7.933 9.768,8.514 10.085,8.906C10.407,9.298 10.827,9.494 11.345,9.494C11.849,9.494 12.244,9.347 12.528,9.053C12.813,8.759 12.967,8.344 12.99,7.807L12.99,7.135L12.017,7.135C11.812,7.135 11.635,7.058 11.485,6.904C11.336,6.745 11.261,6.559 11.261,6.344C11.261,6.125 11.338,5.938 11.492,5.784C11.651,5.625 11.84,5.546 12.059,5.546L14.026,5.546C14.26,5.546 14.458,5.625 14.621,5.784C14.785,5.943 14.869,6.139 14.873,6.372L14.873,7.408C14.873,8.64 14.551,9.594 13.907,10.271C13.268,10.948 12.4,11.286 11.303,11.286ZM16.641,6.09C16.434,6.09 16.256,6.016 16.108,5.867C15.962,5.719 15.89,5.543 15.89,5.338L15.89,0.689C15.89,0.501 15.957,0.34 16.091,0.206C16.226,0.069 16.385,0 16.57,0C16.758,0 16.919,0.069 17.053,0.206C17.187,0.34 17.255,0.501 17.255,0.689L17.255,4.83L18.54,4.83C18.713,4.83 18.863,4.892 18.989,5.015C19.115,5.138 19.178,5.286 19.178,5.46C19.178,5.631 19.115,5.779 18.989,5.905C18.863,6.028 18.713,6.09 18.54,6.09L16.641,6.09ZM20.979,6.166C20.792,6.166 20.63,6.098 20.496,5.964C20.365,5.827 20.299,5.664 20.299,5.477L20.299,0.731L21.664,0.731L21.664,5.477C21.664,5.664 21.597,5.827 21.462,5.964C21.328,6.098 21.167,6.166 20.979,6.166ZM19.648,1.331C19.474,1.331 19.324,1.27 19.198,1.147C19.075,1.023 19.014,0.876 19.014,0.706C19.014,0.532 19.075,0.384 19.198,0.26C19.324,0.137 19.474,0.076 19.648,0.076L22.306,0.076C22.48,0.076 22.628,0.137 22.751,0.26C22.877,0.384 22.941,0.532 22.941,0.706C22.941,0.876 22.877,1.023 22.751,1.147C22.628,1.27 22.48,1.331 22.306,1.331L19.648,1.331ZM24.553,6.09C24.346,6.09 24.168,6.016 24.019,5.867C23.874,5.719 23.801,5.543 23.801,5.338L23.801,0.823C23.801,0.619 23.874,0.444 24.019,0.298C24.168,0.15 24.346,0.076 24.553,0.076L26.59,0.076C26.763,0.076 26.912,0.137 27.035,0.26C27.161,0.384 27.224,0.531 27.224,0.701C27.224,0.872 27.161,1.019 27.035,1.142C26.912,1.266 26.763,1.327 26.59,1.327L25.158,1.327L25.158,4.838L26.657,4.838C26.831,4.838 26.979,4.9 27.102,5.023C27.225,5.146 27.287,5.293 27.287,5.464C27.287,5.635 27.225,5.782 27.102,5.905C26.979,6.028 26.831,6.09 26.657,6.09L24.553,6.09ZM24.637,3.595L24.637,2.444L26.3,2.444C26.46,2.444 26.595,2.5 26.707,2.612C26.822,2.724 26.88,2.86 26.88,3.02C26.88,3.177 26.822,3.312 26.707,3.427C26.595,3.539 26.46,3.595 26.3,3.595L24.637,3.595Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M30.101,5.346C29.923,5.346 29.768,5.282 29.637,5.154C29.509,5.023 29.445,4.867 29.445,4.686L29.445,1.742C29.445,1.561 29.509,1.406 29.637,1.278C29.768,1.147 29.923,1.082 30.101,1.082C30.28,1.082 30.433,1.147 30.561,1.278C30.689,1.406 30.753,1.561 30.753,1.742L30.753,4.686C30.753,4.867 30.689,5.023 30.561,5.154C30.433,5.282 30.28,5.346 30.101,5.346ZM28.677,3.858C28.499,3.858 28.345,3.795 28.217,3.67C28.089,3.542 28.025,3.39 28.025,3.214C28.025,3.038 28.089,2.887 28.217,2.762C28.345,2.634 28.499,2.57 28.677,2.57L31.525,2.57C31.704,2.57 31.857,2.634 31.985,2.762C32.113,2.887 32.177,3.038 32.177,3.214C32.177,3.39 32.113,3.542 31.985,3.67C31.857,3.795 31.704,3.858 31.525,3.858L28.677,3.858Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml
new file mode 100644
index 000000000000..562bcaf2fdba
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="19dp"
+ android:height="13.31dp"
+ android:viewportWidth="14.88"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M4.552,10.325C4.286,10.325 4.058,10.229 3.866,10.038C3.68,9.847 3.586,9.618 3.586,9.352L3.586,7.301L3.74,7.021L3.74,1.953L4.72,2.66L3.712,2.66L1.808,6.496L4.37,6.496L4.797,6.405L5.777,6.405C6.015,6.405 6.218,6.489 6.386,6.657C6.554,6.825 6.638,7.028 6.638,7.266C6.638,7.499 6.554,7.7 6.386,7.868C6.218,8.036 6.015,8.12 5.777,8.12L1.192,8.12C0.856,8.12 0.572,8.01 0.338,7.791C0.11,7.572 -0.005,7.299 -0.005,6.972C-0.005,6.813 0.016,6.699 0.058,6.629C0.1,6.554 0.142,6.48 0.184,6.405L3.124,0.763C3.222,0.576 3.374,0.413 3.579,0.273C3.789,0.133 4.013,0.063 4.251,0.063C4.606,0.063 4.905,0.191 5.147,0.448C5.39,0.7 5.511,1.006 5.511,1.365L5.511,9.352C5.511,9.618 5.416,9.847 5.224,10.038C5.038,10.229 4.814,10.325 4.552,10.325ZM11.303,10.416C10.179,10.411 9.28,10.031 8.608,9.275C7.941,8.514 7.607,7.406 7.607,5.95L7.607,4.417C7.607,2.975 7.948,1.878 8.629,1.127C9.311,0.371 10.223,-0.005 11.366,0C11.88,0 12.314,0.075 12.668,0.224C13.028,0.369 13.333,0.576 13.585,0.847C13.842,1.113 14.019,1.374 14.117,1.631C14.215,1.883 14.222,2.121 14.138,2.345C14.054,2.569 13.91,2.732 13.704,2.835C13.504,2.938 13.308,2.968 13.116,2.926C12.925,2.884 12.776,2.802 12.668,2.681C12.561,2.555 12.451,2.422 12.339,2.282C12.227,2.142 12.087,2.032 11.919,1.953C11.751,1.869 11.551,1.827 11.317,1.827C10.799,1.822 10.384,2.011 10.071,2.394C9.763,2.777 9.609,3.358 9.609,4.137L9.609,6.293C9.609,7.063 9.768,7.644 10.085,8.036C10.407,8.428 10.827,8.624 11.345,8.624C11.849,8.624 12.244,8.477 12.528,8.183C12.813,7.889 12.967,7.474 12.99,6.937L12.99,6.265L12.017,6.265C11.812,6.265 11.635,6.188 11.485,6.034C11.336,5.875 11.261,5.689 11.261,5.474C11.261,5.255 11.338,5.068 11.492,4.914C11.651,4.755 11.84,4.676 12.059,4.676L14.026,4.676C14.26,4.676 14.458,4.755 14.621,4.914C14.785,5.073 14.869,5.269 14.873,5.502L14.873,6.538C14.873,7.77 14.551,8.724 13.907,9.401C13.268,10.078 12.4,10.416 11.303,10.416Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..73e8994681c2
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="23dp"
+ android:height="12.5dp"
+ android:viewportWidth="19.17"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M4.552,10.325C4.286,10.325 4.058,10.229 3.866,10.038C3.68,9.847 3.586,9.618 3.586,9.352L3.586,7.301L3.74,7.021L3.74,1.953L4.72,2.66L3.712,2.66L1.808,6.496L4.37,6.496L4.797,6.405L5.777,6.405C6.015,6.405 6.218,6.489 6.386,6.657C6.554,6.825 6.638,7.028 6.638,7.266C6.638,7.499 6.554,7.7 6.386,7.868C6.218,8.036 6.015,8.12 5.777,8.12L1.192,8.12C0.856,8.12 0.572,8.01 0.338,7.791C0.11,7.572 -0.005,7.299 -0.005,6.972C-0.005,6.813 0.016,6.699 0.058,6.629C0.1,6.554 0.142,6.48 0.184,6.405L3.124,0.763C3.222,0.576 3.374,0.413 3.579,0.273C3.789,0.133 4.013,0.063 4.251,0.063C4.606,0.063 4.905,0.191 5.147,0.448C5.39,0.7 5.511,1.006 5.511,1.365L5.511,9.352C5.511,9.618 5.416,9.847 5.224,10.038C5.038,10.229 4.814,10.325 4.552,10.325ZM11.303,10.416C10.179,10.411 9.28,10.031 8.608,9.275C7.941,8.514 7.607,7.406 7.607,5.95L7.607,4.417C7.607,2.975 7.948,1.878 8.629,1.127C9.311,0.371 10.223,-0.005 11.366,0C11.88,0 12.314,0.075 12.668,0.224C13.028,0.369 13.333,0.576 13.585,0.847C13.842,1.113 14.019,1.374 14.117,1.631C14.215,1.883 14.222,2.121 14.138,2.345C14.054,2.569 13.91,2.732 13.704,2.835C13.504,2.938 13.308,2.968 13.116,2.926C12.925,2.884 12.776,2.802 12.668,2.681C12.561,2.555 12.451,2.422 12.339,2.282C12.227,2.142 12.087,2.032 11.919,1.953C11.751,1.869 11.551,1.827 11.317,1.827C10.799,1.822 10.384,2.011 10.071,2.394C9.763,2.777 9.609,3.358 9.609,4.137L9.609,6.293C9.609,7.063 9.768,7.644 10.085,8.036C10.407,8.428 10.827,8.624 11.345,8.624C11.849,8.624 12.244,8.477 12.528,8.183C12.813,7.889 12.967,7.474 12.99,6.937L12.99,6.265L12.017,6.265C11.812,6.265 11.635,6.188 11.485,6.034C11.336,5.875 11.261,5.689 11.261,5.474C11.261,5.255 11.338,5.068 11.492,4.914C11.651,4.755 11.84,4.676 12.059,4.676L14.026,4.676C14.26,4.676 14.458,4.755 14.621,4.914C14.785,5.073 14.869,5.269 14.873,5.502L14.873,6.538C14.873,7.77 14.551,8.724 13.907,9.401C13.268,10.078 12.4,10.416 11.303,10.416Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M17.086,4.476C16.907,4.476 16.752,4.412 16.622,4.284C16.494,4.153 16.43,3.997 16.43,3.816L16.43,0.872C16.43,0.691 16.494,0.536 16.622,0.408C16.752,0.277 16.907,0.212 17.086,0.212C17.264,0.212 17.418,0.277 17.546,0.408C17.674,0.536 17.738,0.691 17.738,0.872L17.738,3.816C17.738,3.997 17.674,4.153 17.546,4.284C17.418,4.412 17.264,4.476 17.086,4.476ZM15.662,2.988C15.483,2.988 15.33,2.925 15.202,2.8C15.074,2.672 15.01,2.52 15.01,2.344C15.01,2.168 15.074,2.017 15.202,1.892C15.33,1.764 15.483,1.7 15.662,1.7L18.51,1.7C18.688,1.7 18.842,1.764 18.97,1.892C19.098,2.017 19.162,2.168 19.162,2.344C19.162,2.52 19.098,2.672 18.97,2.8C18.842,2.925 18.688,2.988 18.51,2.988L15.662,2.988Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml
new file mode 100644
index 000000000000..c46da66a9183
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="22.0dp"
+ android:height="12.57dp"
+ android:viewportHeight="11.21"
+ android:viewportWidth="19.62">
+
+ <path
+ android:fillColor="#000"
+ android:pathData="M2.573,11.206C1.99,11.206 1.502,11.094 1.11,10.87C0.718,10.641 0.436,10.364 0.263,10.037C0.091,9.706 0.002,9.4 -0.003,9.12C-0.007,8.84 0.058,8.616 0.193,8.448C0.333,8.275 0.499,8.168 0.69,8.126C0.882,8.079 1.057,8.089 1.215,8.154C1.379,8.219 1.502,8.315 1.586,8.441C1.675,8.567 1.75,8.716 1.81,8.889C1.871,9.062 1.971,9.202 2.111,9.309C2.251,9.412 2.429,9.463 2.643,9.463C2.947,9.463 3.203,9.363 3.413,9.162C3.623,8.961 3.763,8.663 3.833,8.266L4.008,7.272C4.074,6.899 4.029,6.609 3.875,6.404C3.726,6.199 3.5,6.096 3.196,6.096C3,6.096 2.825,6.143 2.671,6.236C2.522,6.325 2.401,6.43 2.307,6.551C2.181,6.672 2.03,6.752 1.852,6.789C1.675,6.826 1.488,6.81 1.292,6.74C1.045,6.651 0.865,6.497 0.753,6.278C0.641,6.054 0.62,5.804 0.69,5.529L1.593,1.98C1.677,1.672 1.831,1.429 2.055,1.252C2.284,1.075 2.557,0.986 2.874,0.986L5.674,0.986C5.964,0.986 6.195,1.089 6.367,1.294C6.54,1.495 6.601,1.733 6.549,2.008C6.517,2.213 6.412,2.388 6.234,2.533C6.062,2.673 5.875,2.743 5.674,2.743L3.056,2.743L2.433,5.13L2.475,5.137C2.676,4.955 2.905,4.815 3.161,4.717C3.418,4.614 3.7,4.563 4.008,4.563C4.727,4.563 5.268,4.836 5.632,5.382C6.001,5.923 6.111,6.628 5.961,7.496L5.814,8.336C5.656,9.274 5.299,9.988 4.743,10.478C4.188,10.963 3.465,11.206 2.573,11.206ZM10.577,11.206C9.392,11.206 8.515,10.795 7.945,9.974C7.381,9.153 7.229,8.009 7.49,6.544L7.749,5.039C8.006,3.606 8.498,2.54 9.226,1.84C9.959,1.14 10.883,0.79 11.998,0.79C12.535,0.79 12.995,0.879 13.377,1.056C13.76,1.229 14.059,1.46 14.273,1.749C14.488,2.038 14.612,2.314 14.644,2.575C14.677,2.832 14.644,3.053 14.546,3.24C14.453,3.427 14.313,3.567 14.126,3.66C13.94,3.749 13.753,3.774 13.566,3.737C13.384,3.695 13.244,3.606 13.146,3.471C13.048,3.336 12.941,3.2 12.824,3.065C12.708,2.925 12.57,2.815 12.411,2.736C12.257,2.657 12.068,2.617 11.844,2.617C11.35,2.617 10.918,2.808 10.549,3.191C10.185,3.569 9.936,4.141 9.8,4.906L9.422,7.048C9.287,7.813 9.348,8.399 9.604,8.805C9.861,9.211 10.248,9.414 10.766,9.414C11.256,9.414 11.665,9.267 11.991,8.973C12.318,8.679 12.54,8.264 12.656,7.727L12.775,7.055L11.893,7.055C11.665,7.055 11.48,6.964 11.34,6.782C11.205,6.6 11.158,6.385 11.2,6.138C11.233,5.951 11.326,5.795 11.48,5.669C11.639,5.538 11.809,5.473 11.991,5.473L13.979,5.473C14.25,5.473 14.462,5.566 14.616,5.753C14.775,5.94 14.831,6.168 14.784,6.439L14.595,7.489C14.376,8.702 13.916,9.626 13.216,10.261C12.521,10.891 11.641,11.206 10.577,11.206ZM16.001,6.01C15.799,6.01 15.637,5.937 15.514,5.792C15.39,5.643 15.346,5.47 15.379,5.271L16.181,0.735C16.218,0.53 16.321,0.357 16.492,0.214C16.666,0.068 16.856,-0.004 17.063,-0.004L18.983,-0.004C19.187,-0.004 19.351,0.068 19.474,0.214C19.597,0.36 19.642,0.529 19.609,0.722C19.581,0.868 19.505,0.992 19.382,1.096C19.259,1.197 19.126,1.247 18.983,1.247L17.462,1.247L16.841,4.758L18.21,4.758C18.414,4.758 18.577,4.831 18.697,4.977C18.82,5.122 18.865,5.292 18.832,5.485C18.806,5.631 18.732,5.755 18.609,5.859C18.486,5.96 18.353,6.01 18.21,6.01L16.001,6.01ZM16.526,3.515L16.732,2.364L18.281,2.364C18.472,2.364 18.623,2.432 18.735,2.566C18.847,2.698 18.888,2.853 18.857,3.032C18.832,3.167 18.762,3.281 18.647,3.377C18.535,3.469 18.413,3.515 18.281,3.515L16.526,3.515Z" />
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml
new file mode 100644
index 000000000000..66787b0a7594
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="12.28dp"
+ android:viewportWidth="14.42"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M2.807,10.416C2.247,10.416 1.774,10.325 1.386,10.143C0.999,9.956 0.684,9.704 0.441,9.387C0.199,9.065 0.056,8.745 0.014,8.428C-0.028,8.111 0.014,7.859 0.14,7.672C0.271,7.485 0.439,7.366 0.644,7.315C0.85,7.259 1.036,7.266 1.204,7.336C1.372,7.406 1.494,7.506 1.568,7.637C1.643,7.763 1.727,7.912 1.82,8.085C1.914,8.253 2.03,8.393 2.17,8.505C2.315,8.617 2.504,8.673 2.737,8.673C3.055,8.673 3.309,8.57 3.5,8.365C3.696,8.16 3.794,7.849 3.794,7.434L3.794,6.461C3.794,6.083 3.701,5.796 3.514,5.6C3.332,5.399 3.092,5.299 2.793,5.299C2.593,5.299 2.427,5.341 2.296,5.425C2.166,5.509 2.054,5.605 1.96,5.712C1.858,5.819 1.715,5.901 1.533,5.957C1.351,6.008 1.148,6.001 0.924,5.936C0.682,5.861 0.49,5.714 0.35,5.495C0.215,5.271 0.159,5.035 0.182,4.788L0.455,1.281C0.483,0.987 0.614,0.733 0.847,0.518C1.081,0.303 1.347,0.196 1.645,0.196L4.515,0.196C4.758,0.196 4.966,0.282 5.138,0.455C5.316,0.628 5.404,0.833 5.404,1.071C5.404,1.314 5.316,1.521 5.138,1.694C4.966,1.867 4.758,1.953 4.515,1.953L2.044,1.953L1.841,4.34L1.897,4.354C2.07,4.172 2.285,4.03 2.541,3.927C2.803,3.824 3.094,3.773 3.416,3.773C4.126,3.773 4.697,4.02 5.131,4.515C5.565,5.005 5.782,5.677 5.782,6.531L5.782,7.378C5.782,8.33 5.516,9.074 4.984,9.611C4.452,10.148 3.727,10.416 2.807,10.416ZM10.853,10.416C9.729,10.411 8.83,10.031 8.158,9.275C7.491,8.514 7.157,7.406 7.157,5.95L7.157,4.417C7.157,2.975 7.498,1.878 8.179,1.127C8.861,0.371 9.773,-0.005 10.916,0C11.43,0 11.864,0.075 12.218,0.224C12.578,0.369 12.883,0.576 13.135,0.847C13.392,1.113 13.569,1.374 13.667,1.631C13.765,1.883 13.772,2.121 13.688,2.345C13.604,2.569 13.46,2.732 13.254,2.835C13.054,2.938 12.858,2.968 12.666,2.926C12.475,2.884 12.326,2.802 12.218,2.681C12.111,2.555 12.001,2.422 11.889,2.282C11.777,2.142 11.637,2.032 11.469,1.953C11.301,1.869 11.101,1.827 10.867,1.827C10.349,1.822 9.934,2.011 9.621,2.394C9.313,2.777 9.159,3.358 9.159,4.137L9.159,6.293C9.159,7.063 9.318,7.644 9.635,8.036C9.957,8.428 10.377,8.624 10.895,8.624C11.399,8.624 11.794,8.477 12.078,8.183C12.363,7.889 12.517,7.474 12.54,6.937L12.54,6.265L11.567,6.265C11.362,6.265 11.185,6.188 11.035,6.034C10.886,5.875 10.811,5.689 10.811,5.474C10.811,5.255 10.888,5.068 11.042,4.914C11.201,4.755 11.39,4.676 11.609,4.676L13.576,4.676C13.81,4.676 14.008,4.755 14.171,4.914C14.335,5.073 14.419,5.269 14.423,5.502L14.423,6.538C14.423,7.77 14.101,8.724 13.457,9.401C12.818,10.078 11.95,10.416 10.853,10.416Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml
new file mode 100644
index 000000000000..5ba3c98028a2
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="22dp"
+ android:height="11.63dp"
+ android:viewportWidth="19.71"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M2.807,10.416C2.247,10.416 1.774,10.325 1.386,10.143C0.999,9.956 0.684,9.704 0.441,9.387C0.199,9.065 0.056,8.745 0.014,8.428C-0.028,8.111 0.014,7.859 0.14,7.672C0.271,7.485 0.439,7.366 0.644,7.315C0.85,7.259 1.036,7.266 1.204,7.336C1.372,7.406 1.494,7.506 1.568,7.637C1.643,7.763 1.727,7.912 1.82,8.085C1.914,8.253 2.03,8.393 2.17,8.505C2.315,8.617 2.504,8.673 2.737,8.673C3.055,8.673 3.309,8.57 3.5,8.365C3.696,8.16 3.794,7.849 3.794,7.434L3.794,6.461C3.794,6.083 3.701,5.796 3.514,5.6C3.332,5.399 3.092,5.299 2.793,5.299C2.593,5.299 2.427,5.341 2.296,5.425C2.166,5.509 2.054,5.605 1.96,5.712C1.858,5.819 1.715,5.901 1.533,5.957C1.351,6.008 1.148,6.001 0.924,5.936C0.682,5.861 0.49,5.714 0.35,5.495C0.215,5.271 0.159,5.035 0.182,4.788L0.455,1.281C0.483,0.987 0.614,0.733 0.847,0.518C1.081,0.303 1.347,0.196 1.645,0.196L4.515,0.196C4.758,0.196 4.966,0.282 5.138,0.455C5.316,0.628 5.404,0.833 5.404,1.071C5.404,1.314 5.316,1.521 5.138,1.694C4.966,1.867 4.758,1.953 4.515,1.953L2.044,1.953L1.841,4.34L1.897,4.354C2.07,4.172 2.285,4.03 2.541,3.927C2.803,3.824 3.094,3.773 3.416,3.773C4.126,3.773 4.697,4.02 5.131,4.515C5.565,5.005 5.782,5.677 5.782,6.531L5.782,7.378C5.782,8.33 5.516,9.074 4.984,9.611C4.452,10.148 3.727,10.416 2.807,10.416ZM10.853,10.416C9.729,10.411 8.83,10.031 8.158,9.275C7.491,8.514 7.157,7.406 7.157,5.95L7.157,4.417C7.157,2.975 7.498,1.878 8.179,1.127C8.861,0.371 9.773,-0.005 10.916,0C11.43,0 11.864,0.075 12.218,0.224C12.578,0.369 12.883,0.576 13.135,0.847C13.392,1.113 13.569,1.374 13.667,1.631C13.765,1.883 13.772,2.121 13.688,2.345C13.604,2.569 13.46,2.732 13.254,2.835C13.054,2.938 12.858,2.968 12.666,2.926C12.475,2.884 12.326,2.802 12.218,2.681C12.111,2.555 12.001,2.422 11.889,2.282C11.777,2.142 11.637,2.032 11.469,1.953C11.301,1.869 11.101,1.827 10.867,1.827C10.349,1.822 9.934,2.011 9.621,2.394C9.313,2.777 9.159,3.358 9.159,4.137L9.159,6.293C9.159,7.063 9.318,7.644 9.635,8.036C9.957,8.428 10.377,8.624 10.895,8.624C11.399,8.624 11.794,8.477 12.078,8.183C12.363,7.889 12.517,7.474 12.54,6.937L12.54,6.265L11.567,6.265C11.362,6.265 11.185,6.188 11.035,6.034C10.886,5.875 10.811,5.689 10.811,5.474C10.811,5.255 10.888,5.068 11.042,4.914C11.201,4.755 11.39,4.676 11.609,4.676L13.576,4.676C13.81,4.676 14.008,4.755 14.171,4.914C14.335,5.073 14.419,5.269 14.423,5.502L14.423,6.538C14.423,7.77 14.101,8.724 13.457,9.401C12.818,10.078 11.95,10.416 10.853,10.416Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M17.636,4.476C17.457,4.476 17.302,4.412 17.172,4.284C17.044,4.153 16.98,3.997 16.98,3.816L16.98,0.872C16.98,0.691 17.044,0.536 17.172,0.408C17.302,0.277 17.457,0.212 17.636,0.212C17.814,0.212 17.968,0.277 18.096,0.408C18.224,0.536 18.288,0.691 18.288,0.872L18.288,3.816C18.288,3.997 18.224,4.153 18.096,4.284C17.968,4.412 17.814,4.476 17.636,4.476ZM16.212,2.988C16.033,2.988 15.88,2.925 15.752,2.8C15.624,2.672 15.56,2.52 15.56,2.344C15.56,2.168 15.624,2.017 15.752,1.892C15.88,1.764 16.033,1.7 16.212,1.7L19.06,1.7C19.238,1.7 19.392,1.764 19.52,1.892C19.648,2.017 19.712,2.168 19.712,2.344C19.712,2.52 19.648,2.672 19.52,2.8C19.392,2.925 19.238,2.988 19.06,2.988L16.212,2.988Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..5ba3c98028a2
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="22dp"
+ android:height="11.63dp"
+ android:viewportWidth="19.71"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M2.807,10.416C2.247,10.416 1.774,10.325 1.386,10.143C0.999,9.956 0.684,9.704 0.441,9.387C0.199,9.065 0.056,8.745 0.014,8.428C-0.028,8.111 0.014,7.859 0.14,7.672C0.271,7.485 0.439,7.366 0.644,7.315C0.85,7.259 1.036,7.266 1.204,7.336C1.372,7.406 1.494,7.506 1.568,7.637C1.643,7.763 1.727,7.912 1.82,8.085C1.914,8.253 2.03,8.393 2.17,8.505C2.315,8.617 2.504,8.673 2.737,8.673C3.055,8.673 3.309,8.57 3.5,8.365C3.696,8.16 3.794,7.849 3.794,7.434L3.794,6.461C3.794,6.083 3.701,5.796 3.514,5.6C3.332,5.399 3.092,5.299 2.793,5.299C2.593,5.299 2.427,5.341 2.296,5.425C2.166,5.509 2.054,5.605 1.96,5.712C1.858,5.819 1.715,5.901 1.533,5.957C1.351,6.008 1.148,6.001 0.924,5.936C0.682,5.861 0.49,5.714 0.35,5.495C0.215,5.271 0.159,5.035 0.182,4.788L0.455,1.281C0.483,0.987 0.614,0.733 0.847,0.518C1.081,0.303 1.347,0.196 1.645,0.196L4.515,0.196C4.758,0.196 4.966,0.282 5.138,0.455C5.316,0.628 5.404,0.833 5.404,1.071C5.404,1.314 5.316,1.521 5.138,1.694C4.966,1.867 4.758,1.953 4.515,1.953L2.044,1.953L1.841,4.34L1.897,4.354C2.07,4.172 2.285,4.03 2.541,3.927C2.803,3.824 3.094,3.773 3.416,3.773C4.126,3.773 4.697,4.02 5.131,4.515C5.565,5.005 5.782,5.677 5.782,6.531L5.782,7.378C5.782,8.33 5.516,9.074 4.984,9.611C4.452,10.148 3.727,10.416 2.807,10.416ZM10.853,10.416C9.729,10.411 8.83,10.031 8.158,9.275C7.491,8.514 7.157,7.406 7.157,5.95L7.157,4.417C7.157,2.975 7.498,1.878 8.179,1.127C8.861,0.371 9.773,-0.005 10.916,0C11.43,0 11.864,0.075 12.218,0.224C12.578,0.369 12.883,0.576 13.135,0.847C13.392,1.113 13.569,1.374 13.667,1.631C13.765,1.883 13.772,2.121 13.688,2.345C13.604,2.569 13.46,2.732 13.254,2.835C13.054,2.938 12.858,2.968 12.666,2.926C12.475,2.884 12.326,2.802 12.218,2.681C12.111,2.555 12.001,2.422 11.889,2.282C11.777,2.142 11.637,2.032 11.469,1.953C11.301,1.869 11.101,1.827 10.867,1.827C10.349,1.822 9.934,2.011 9.621,2.394C9.313,2.777 9.159,3.358 9.159,4.137L9.159,6.293C9.159,7.063 9.318,7.644 9.635,8.036C9.957,8.428 10.377,8.624 10.895,8.624C11.399,8.624 11.794,8.477 12.078,8.183C12.363,7.889 12.517,7.474 12.54,6.937L12.54,6.265L11.567,6.265C11.362,6.265 11.185,6.188 11.035,6.034C10.886,5.875 10.811,5.689 10.811,5.474C10.811,5.255 10.888,5.068 11.042,4.914C11.201,4.755 11.39,4.676 11.609,4.676L13.576,4.676C13.81,4.676 14.008,4.755 14.171,4.914C14.335,5.073 14.419,5.269 14.423,5.502L14.423,6.538C14.423,7.77 14.101,8.724 13.457,9.401C12.818,10.078 11.95,10.416 10.853,10.416Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M17.636,4.476C17.457,4.476 17.302,4.412 17.172,4.284C17.044,4.153 16.98,3.997 16.98,3.816L16.98,0.872C16.98,0.691 17.044,0.536 17.172,0.408C17.302,0.277 17.457,0.212 17.636,0.212C17.814,0.212 17.968,0.277 18.096,0.408C18.224,0.536 18.288,0.691 18.288,0.872L18.288,3.816C18.288,3.997 18.224,4.153 18.096,4.284C17.968,4.412 17.814,4.476 17.636,4.476ZM16.212,2.988C16.033,2.988 15.88,2.925 15.752,2.8C15.624,2.672 15.56,2.52 15.56,2.344C15.56,2.168 15.624,2.017 15.752,1.892C15.88,1.764 16.033,1.7 16.212,1.7L19.06,1.7C19.238,1.7 19.392,1.764 19.52,1.892C19.648,2.017 19.712,2.168 19.712,2.344C19.712,2.52 19.648,2.672 19.52,2.8C19.392,2.925 19.238,2.988 19.06,2.988L16.212,2.988Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml b/packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml
new file mode 100644
index 000000000000..14db82614ad1
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2025 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="19.0dp"
+ android:height="12.38dp"
+ android:viewportHeight="10.26"
+ android:viewportWidth="15.75">
+
+ <path
+ android:fillColor="#000"
+ android:pathData="M2.864,10.259C2.598,10.259 2.358,10.168 2.143,9.986C1.929,9.804 1.793,9.589 1.737,9.342L0.036,1.208C-0.043,0.877 0.013,0.594 0.204,0.361C0.4,0.128 0.657,0.011 0.974,0.011C1.208,0.011 1.418,0.093 1.604,0.256C1.791,0.419 1.908,0.611 1.954,0.83L2.885,5.828L3.039,6.92L3.088,6.92L3.249,5.828L4.278,0.851C4.325,0.622 4.446,0.424 4.642,0.256C4.843,0.088 5.065,0.004 5.307,0.004C5.55,0.004 5.769,0.088 5.965,0.256C6.166,0.424 6.292,0.625 6.343,0.858L7.358,5.814L7.526,6.913L7.575,6.913L7.729,5.814L8.653,0.781C8.695,0.571 8.805,0.391 8.982,0.242C9.16,0.093 9.356,0.018 9.57,0.018C9.874,0.018 10.114,0.128 10.291,0.347C10.473,0.566 10.529,0.828 10.459,1.131L8.765,9.342C8.709,9.594 8.574,9.811 8.359,9.993C8.145,10.17 7.902,10.259 7.631,10.259C7.37,10.259 7.132,10.17 6.917,9.993C6.703,9.811 6.57,9.594 6.518,9.342L5.44,4.19L5.279,3.133L5.23,3.133L5.069,4.183L3.977,9.342C3.926,9.589 3.793,9.804 3.578,9.986C3.364,10.168 3.126,10.259 2.864,10.259Z" />
+
+ <path
+ android:fillColor="#000"
+ android:pathData="M13.676,4.396C13.497,4.396 13.342,4.332 13.212,4.204C13.084,4.073 13.02,3.917 13.02,3.736L13.02,0.792C13.02,0.611 13.084,0.456 13.212,0.328C13.342,0.197 13.497,0.132 13.676,0.132C13.854,0.132 14.008,0.197 14.136,0.328C14.264,0.456 14.328,0.611 14.328,0.792L14.328,3.736C14.328,3.917 14.264,4.073 14.136,4.204C14.008,4.332 13.854,4.396 13.676,4.396ZM12.252,2.908C12.073,2.908 11.92,2.845 11.792,2.72C11.664,2.592 11.6,2.44 11.6,2.264C11.6,2.088 11.664,1.937 11.792,1.812C11.92,1.684 12.073,1.62 12.252,1.62L15.1,1.62C15.278,1.62 15.432,1.684 15.56,1.812C15.688,1.937 15.752,2.088 15.752,2.264C15.752,2.44 15.688,2.592 15.56,2.72C15.432,2.845 15.278,2.908 15.1,2.908L12.252,2.908Z" />
+
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml
new file mode 100644
index 000000000000..febcd87efbc3
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="31.08dp"
+ android:viewportWidth="5.48"
+ android:viewportHeight="10.02">
+ <path
+ android:pathData="M1.081,10.02C0.787,10.02 0.533,9.913 0.318,9.698C0.104,9.483 -0.004,9.229 -0.004,8.935L-0.004,1.081C-0.004,0.787 0.104,0.533 0.318,0.318C0.533,0.103 0.787,-0.004 1.081,-0.004L4.455,-0.004C4.707,-0.004 4.922,0.087 5.099,0.269C5.281,0.446 5.372,0.659 5.372,0.906C5.372,1.153 5.281,1.368 5.099,1.55C4.922,1.727 4.707,1.816 4.455,1.816L1.963,1.816L1.963,8.2L4.56,8.2C4.812,8.2 5.027,8.291 5.204,8.473C5.386,8.65 5.477,8.863 5.477,9.11C5.477,9.357 5.386,9.572 5.204,9.754C5.027,9.931 4.812,10.02 4.56,10.02L1.081,10.02ZM1.186,5.736L1.186,4.042L3.951,4.042C4.185,4.042 4.385,4.126 4.553,4.294C4.721,4.457 4.805,4.656 4.805,4.889C4.805,5.118 4.721,5.316 4.553,5.484C4.385,5.652 4.185,5.736 3.951,5.736L1.186,5.736Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml
new file mode 100644
index 000000000000..d719f7a05aa0
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="24.37dp"
+ android:viewportWidth="7.27"
+ android:viewportHeight="10.42">
+ <path
+ android:pathData="M3.696,10.416C2.571,10.411 1.673,10.031 1.001,9.275C0.333,8.514 -0,7.406 -0,5.95L-0,4.417C-0,2.975 0.34,1.878 1.022,1.127C1.703,0.371 2.615,-0.005 3.759,0C4.272,0 4.706,0.075 5.061,0.224C5.42,0.369 5.726,0.576 5.978,0.847C6.235,1.113 6.412,1.374 6.51,1.631C6.608,1.883 6.615,2.121 6.531,2.345C6.447,2.569 6.302,2.732 6.097,2.835C5.896,2.938 5.7,2.968 5.509,2.926C5.317,2.884 5.168,2.802 5.061,2.681C4.953,2.555 4.844,2.422 4.732,2.282C4.62,2.142 4.48,2.032 4.312,1.953C4.144,1.869 3.943,1.827 3.71,1.827C3.192,1.822 2.776,2.011 2.464,2.394C2.156,2.777 2.002,3.358 2.002,4.137L2.002,6.293C2.002,7.063 2.16,7.644 2.478,8.036C2.8,8.428 3.22,8.624 3.738,8.624C4.242,8.624 4.636,8.477 4.921,8.183C5.205,7.889 5.359,7.474 5.383,6.937L5.383,6.265L4.41,6.265C4.204,6.265 4.027,6.188 3.878,6.034C3.728,5.875 3.654,5.689 3.654,5.474C3.654,5.255 3.731,5.068 3.885,4.914C4.043,4.755 4.232,4.676 4.452,4.676L6.419,4.676C6.652,4.676 6.85,4.755 7.014,4.914C7.177,5.073 7.261,5.269 7.266,5.502L7.266,6.538C7.266,7.77 6.944,8.724 6.3,9.401C5.661,10.078 4.792,10.416 3.696,10.416Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml
new file mode 100644
index 000000000000..e60ff8cde396
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="26.68dp"
+ android:viewportWidth="6.53"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M5.547,10.252C5.277,10.252 5.043,10.154 4.847,9.958C4.656,9.757 4.56,9.522 4.56,9.251L4.56,1.005C4.56,0.73 4.656,0.494 4.847,0.298C5.043,0.102 5.277,0.004 5.547,0.004C5.818,0.004 6.049,0.102 6.24,0.298C6.436,0.494 6.534,0.73 6.534,1.005L6.534,9.251C6.534,9.522 6.436,9.757 6.24,9.958C6.049,10.154 5.818,10.252 5.547,10.252ZM0.99,10.252C0.72,10.252 0.486,10.154 0.29,9.958C0.099,9.757 0.003,9.522 0.003,9.251L0.003,1.005C0.003,0.73 0.099,0.494 0.29,0.298C0.486,0.102 0.72,0.004 0.99,0.004C1.261,0.004 1.492,0.102 1.683,0.298C1.879,0.494 1.977,0.73 1.977,1.005L1.977,9.251C1.977,9.522 1.879,9.757 1.683,9.958C1.492,10.154 1.261,10.252 0.99,10.252ZM1.151,5.933L1.151,4.106L5.484,4.106L5.484,5.933L1.151,5.933Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..e02df563dfdd
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="13.52dp"
+ android:viewportWidth="12.13"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M5.541,10.252C5.271,10.252 5.037,10.154 4.841,9.958C4.65,9.757 4.554,9.522 4.554,9.251L4.554,1.005C4.554,0.73 4.65,0.494 4.841,0.298C5.037,0.102 5.271,0.004 5.541,0.004C5.812,0.004 6.043,0.102 6.234,0.298C6.43,0.494 6.528,0.73 6.528,1.005L6.528,9.251C6.528,9.522 6.43,9.757 6.234,9.958C6.043,10.154 5.812,10.252 5.541,10.252ZM0.984,10.252C0.714,10.252 0.48,10.154 0.284,9.958C0.093,9.757 -0.003,9.522 -0.003,9.251L-0.003,1.005C-0.003,0.73 0.093,0.494 0.284,0.298C0.48,0.102 0.714,0.004 0.984,0.004C1.255,0.004 1.486,0.102 1.677,0.298C1.873,0.494 1.971,0.73 1.971,1.005L1.971,9.251C1.971,9.522 1.873,9.757 1.677,9.958C1.486,10.154 1.255,10.252 0.984,10.252ZM1.145,5.933L1.145,4.106L5.478,4.106L5.478,5.933L1.145,5.933Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M10.056,4.396C9.877,4.396 9.722,4.332 9.592,4.204C9.464,4.073 9.4,3.917 9.4,3.736L9.4,0.792C9.4,0.611 9.464,0.456 9.592,0.328C9.722,0.197 9.877,0.132 10.056,0.132C10.234,0.132 10.388,0.197 10.516,0.328C10.644,0.456 10.708,0.611 10.708,0.792L10.708,3.736C10.708,3.917 10.644,4.073 10.516,4.204C10.388,4.332 10.234,4.396 10.056,4.396ZM8.632,2.908C8.453,2.908 8.3,2.845 8.172,2.72C8.044,2.592 7.98,2.44 7.98,2.264C7.98,2.088 8.044,1.937 8.172,1.812C8.3,1.684 8.453,1.62 8.632,1.62L11.48,1.62C11.658,1.62 11.812,1.684 11.94,1.812C12.068,1.937 12.132,2.088 12.132,2.264C12.132,2.44 12.068,2.592 11.94,2.72C11.812,2.845 11.658,2.908 11.48,2.908L8.632,2.908Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml
new file mode 100644
index 000000000000..9d64439cf30b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="11.92dp"
+ android:viewportWidth="17.2"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M1.082,10.14C0.788,10.14 0.534,10.033 0.319,9.818C0.105,9.603 -0.003,9.349 -0.003,9.055L-0.003,1.005C-0.003,0.73 0.093,0.494 0.284,0.298C0.48,0.102 0.714,0.004 0.984,0.004C1.255,0.004 1.486,0.102 1.677,0.298C1.873,0.494 1.971,0.73 1.971,1.005L1.971,8.313L4.19,8.313C4.442,8.313 4.659,8.404 4.841,8.586C5.023,8.763 5.114,8.976 5.114,9.223C5.114,9.475 5.023,9.692 4.841,9.874C4.659,10.051 4.442,10.14 4.19,10.14L1.082,10.14ZM7.59,10.252C7.32,10.252 7.086,10.154 6.89,9.958C6.694,9.757 6.596,9.522 6.596,9.251L6.596,1.068L8.577,1.068L8.577,9.251C8.577,9.522 8.479,9.757 8.283,9.958C8.087,10.154 7.856,10.252 7.59,10.252ZM5.413,1.936C5.161,1.936 4.944,1.847 4.762,1.67C4.585,1.488 4.496,1.273 4.496,1.026C4.496,0.779 4.585,0.566 4.762,0.389C4.944,0.207 5.161,0.116 5.413,0.116L9.753,0.116C10.005,0.116 10.222,0.207 10.404,0.389C10.586,0.566 10.677,0.779 10.677,1.026C10.677,1.273 10.586,1.488 10.404,1.67C10.222,1.847 10.005,1.936 9.753,1.936L5.413,1.936ZM12.799,10.14C12.505,10.14 12.251,10.033 12.036,9.818C11.821,9.603 11.714,9.349 11.714,9.055L11.714,1.201C11.714,0.907 11.821,0.653 12.036,0.438C12.251,0.223 12.505,0.116 12.799,0.116L16.173,0.116C16.425,0.116 16.64,0.207 16.817,0.389C16.999,0.566 17.09,0.779 17.09,1.026C17.09,1.273 16.999,1.488 16.817,1.67C16.64,1.847 16.425,1.936 16.173,1.936L13.681,1.936L13.681,8.32L16.278,8.32C16.53,8.32 16.745,8.411 16.922,8.593C17.104,8.77 17.195,8.983 17.195,9.23C17.195,9.477 17.104,9.692 16.922,9.874C16.745,10.051 16.53,10.14 16.278,10.14L12.799,10.14ZM12.904,5.856L12.904,4.162L15.669,4.162C15.902,4.162 16.103,4.246 16.271,4.414C16.439,4.577 16.523,4.776 16.523,5.009C16.523,5.238 16.439,5.436 16.271,5.604C16.103,5.772 15.902,5.856 15.669,5.856L12.904,5.856Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml
new file mode 100644
index 000000000000..7075516e6dd3
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2025 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="25dp"
+ android:height="11.85dp"
+ android:viewportWidth="21.63"
+ android:viewportHeight="10.25">
+ <path
+ android:pathData="M1.082,10.14C0.788,10.14 0.534,10.033 0.319,9.818C0.105,9.603 -0.003,9.349 -0.003,9.055L-0.003,1.005C-0.003,0.73 0.093,0.494 0.284,0.298C0.48,0.102 0.714,0.004 0.984,0.004C1.255,0.004 1.486,0.102 1.677,0.298C1.873,0.494 1.971,0.73 1.971,1.005L1.971,8.313L4.19,8.313C4.442,8.313 4.659,8.404 4.841,8.586C5.023,8.763 5.114,8.976 5.114,9.223C5.114,9.475 5.023,9.692 4.841,9.874C4.659,10.051 4.442,10.14 4.19,10.14L1.082,10.14ZM7.59,10.252C7.32,10.252 7.086,10.154 6.89,9.958C6.694,9.757 6.596,9.522 6.596,9.251L6.596,1.068L8.577,1.068L8.577,9.251C8.577,9.522 8.479,9.757 8.283,9.958C8.087,10.154 7.856,10.252 7.59,10.252ZM5.413,1.936C5.161,1.936 4.944,1.847 4.762,1.67C4.585,1.488 4.496,1.273 4.496,1.026C4.496,0.779 4.585,0.566 4.762,0.389C4.944,0.207 5.161,0.116 5.413,0.116L9.753,0.116C10.005,0.116 10.222,0.207 10.404,0.389C10.586,0.566 10.677,0.779 10.677,1.026C10.677,1.273 10.586,1.488 10.404,1.67C10.222,1.847 10.005,1.936 9.753,1.936L5.413,1.936ZM12.799,10.14C12.505,10.14 12.251,10.033 12.036,9.818C11.821,9.603 11.714,9.349 11.714,9.055L11.714,1.201C11.714,0.907 11.821,0.653 12.036,0.438C12.251,0.223 12.505,0.116 12.799,0.116L16.173,0.116C16.425,0.116 16.64,0.207 16.817,0.389C16.999,0.566 17.09,0.779 17.09,1.026C17.09,1.273 16.999,1.488 16.817,1.67C16.64,1.847 16.425,1.936 16.173,1.936L13.681,1.936L13.681,8.32L16.278,8.32C16.53,8.32 16.745,8.411 16.922,8.593C17.104,8.77 17.195,8.983 17.195,9.23C17.195,9.477 17.104,9.692 16.922,9.874C16.745,10.051 16.53,10.14 16.278,10.14L12.799,10.14ZM12.904,5.856L12.904,4.162L15.669,4.162C15.902,4.162 16.103,4.246 16.271,4.414C16.439,4.577 16.523,4.776 16.523,5.009C16.523,5.238 16.439,5.436 16.271,5.604C16.103,5.772 15.902,5.856 15.669,5.856L12.904,5.856Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M19.556,4.396C19.377,4.396 19.222,4.332 19.092,4.204C18.964,4.073 18.9,3.917 18.9,3.736L18.9,0.792C18.9,0.611 18.964,0.456 19.092,0.328C19.222,0.197 19.377,0.132 19.556,0.132C19.734,0.132 19.888,0.197 20.016,0.328C20.144,0.456 20.208,0.611 20.208,0.792L20.208,3.736C20.208,3.917 20.144,4.073 20.016,4.204C19.888,4.332 19.734,4.396 19.556,4.396ZM18.132,2.908C17.953,2.908 17.8,2.845 17.672,2.72C17.544,2.592 17.48,2.44 17.48,2.264C17.48,2.088 17.544,1.937 17.672,1.812C17.8,1.684 17.953,1.62 18.132,1.62L20.98,1.62C21.158,1.62 21.312,1.684 21.44,1.812C21.568,1.937 21.632,2.088 21.632,2.264C21.632,2.44 21.568,2.592 21.44,2.72C21.312,2.845 21.158,2.908 20.98,2.908L18.132,2.908Z"
+ android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml
index d9a417f1ea99..54c878810d10 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2023 The Android Open Source Project
+ Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,24 +14,24 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="14dp"
- android:height="14dp"
- android:viewportWidth="14.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
<path
- android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
- android:fillAlpha="0.24"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
- android:fillAlpha="0.24"
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
- android:fillAlpha="0.24"
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
- android:fillAlpha="0.24"
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml
index facc285a45ca..6015be8c894f 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml
@@ -1,28 +1,51 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="15dp"
- android:height="14dp"
- android:viewportWidth="15.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
+ <group>
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <clip-path
+ android:pathData="
+ M0,0
+ V13.5,0
+ H13.5,20
+ V0,20
+ H0,0
+ M14.999,13.5C17.761,13.5 19.999,11.261 19.999,8.5C19.999,5.739 17.761,3.5 14.999,3.5C12.238,3.5 9.999,5.739 9.999,8.5C9.999,11.261 12.238,13.5 14.999,13.5Z" />
+ <path
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ </group>
<path
- android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+ android:pathData="M14.999,5C14.589,5 14.249,5.34 14.249,5.75L14.249,8.75C14.249,9.16 14.589,9.5 14.999,9.5C15.409,9.5 15.749,9.16 15.749,8.75L15.749,5.75C15.749,5.34 15.409,5 14.999,5ZM14.999,12C15.409,12 15.749,11.66 15.749,11.25C15.749,10.84 15.409,10.5 14.999,10.5C14.589,10.5 14.249,10.84 14.249,11.25C14.249,11.66 14.589,12 14.999,12Z"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml
index 2c05a938c2cf..7c85b9e44383 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml
@@ -14,28 +14,28 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="14dp"
- android:viewportWidth="16.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportWidth="20.5"
+ android:viewportHeight="12.0">
<path
- android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
- android:fillAlpha="0.24"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
- android:fillAlpha="0.24"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
- android:fillAlpha="0.24"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
- android:fillAlpha="0.24"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
- android:fillAlpha="0.24"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml
index 328e45ec7e19..f75ec57f2a5e 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml
@@ -1,32 +1,54 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="14dp"
- android:viewportWidth="18.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportHeight="12.0"
+ android:viewportWidth="20.5">
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <group>
+ <clip-path android:pathData="
+ M0,0
+ H20.5
+ V12.0
+ H0
+ Z
+ M19.499,13.5C22.261,13.5 24.499,11.261 24.499,8.5C24.499,5.739 22.261,3.5 19.499,3.5C16.738,3.5 14.499,5.739 14.499,8.5C14.499,11.261 16.738,13.5 19.499,13.5Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z" />
+ </group>
<path
- android:pathData="M14,0.5C14,0.224 14.224,0 14.5,0H15.5C15.776,0 16,0.224 16,0.5V3H14V0.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M0.5,11C0.224,11 0,11.224 0,11.5V13.5C0,13.776 0.224,14 0.5,14H1.5C1.776,14 2,13.776 2,13.5V11.5C2,11.224 1.776,11 1.5,11H0.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M4,8C3.724,8 3.5,8.224 3.5,8.5V13.5C3.5,13.776 3.724,14 4,14H5C5.276,14 5.5,13.776 5.5,13.5V8.5C5.5,8.224 5.276,8 5,8H4Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
- android:fillColor="#000"/>
+ android:fillColor="#000"
+ android:pathData="M19.499,5C19.089,5 18.749,5.34 18.749,5.75L18.749,8.75C18.749,9.16 19.089,9.5 19.499,9.5C19.909,9.5 20.249,9.16 20.249,8.75L20.249,5.75C20.249,5.34 19.909,5 19.499,5ZM19.499,12C19.909,12 20.249,11.66 20.249,11.25C20.249,10.84 19.909,10.5 19.499,10.5C19.089,10.5 18.749,10.84 18.749,11.25C18.749,11.66 19.089,12 19.499,12Z" />
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml
index b9054ba7a4e3..df89aef3b63d 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml
@@ -14,23 +14,23 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="14dp"
- android:height="14dp"
- android:viewportWidth="14.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
<path
- android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
- android:fillAlpha="0.24"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
android:fillColor="#000"/>
<path
- android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
- android:fillAlpha="0.24"
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
- android:fillAlpha="0.24"
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml
index 03a93491491c..fb73b6b253e1 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml
@@ -1,27 +1,35 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="15dp"
- android:height="14dp"
- android:viewportWidth="15.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
+ <group>
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <clip-path
+ android:pathData="
+ M0,0
+ V13.5,0
+ H13.5,20
+ V0,20
+ H0,0
+ M14.999,13.5C17.761,13.5 19.999,11.261 19.999,8.5C19.999,5.739 17.761,3.5 14.999,3.5C12.238,3.5 9.999,5.739 9.999,8.5C9.999,11.261 12.238,13.5 14.999,13.5Z" />
+ <path
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ </group>
<path
- android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+ android:pathData="M14.999,5C14.589,5 14.249,5.34 14.249,5.75L14.249,8.75C14.249,9.16 14.589,9.5 14.999,9.5C15.409,9.5 15.749,9.16 15.749,8.75L15.749,5.75C15.749,5.34 15.409,5 14.999,5ZM14.999,12C15.409,12 15.749,11.66 15.749,11.25C15.749,10.84 15.409,10.5 14.999,10.5C14.589,10.5 14.249,10.84 14.249,11.25C14.249,11.66 14.589,12 14.999,12Z"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml
index 774e91794df3..5b7d8daa74f2 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml
@@ -14,27 +14,27 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="14dp"
- android:viewportWidth="16.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportWidth="20.5"
+ android:viewportHeight="12.0">
<path
- android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
- android:fillAlpha="0.24"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
android:fillColor="#000"/>
<path
- android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
- android:fillAlpha="0.24"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
- android:fillAlpha="0.24"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
- android:fillAlpha="0.24"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml
index 343ec1b2e50f..27e233d244c7 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml
@@ -1,31 +1,53 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="14dp"
- android:viewportWidth="18.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportHeight="12.0"
+ android:viewportWidth="20.5">
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <group>
+ <clip-path android:pathData="
+ M0,0
+ H20.5
+ V12.0
+ H0
+ Z
+ M19.499,13.5C22.261,13.5 24.499,11.261 24.499,8.5C24.499,5.739 22.261,3.5 19.499,3.5C16.738,3.5 14.499,5.739 14.499,8.5C14.499,11.261 16.738,13.5 19.499,13.5Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z" />
+ </group>
<path
- android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
- android:fillColor="#000"/>
+ android:fillColor="#000"
+ android:pathData="M19.499,5C19.089,5 18.749,5.34 18.749,5.75L18.749,8.75C18.749,9.16 19.089,9.5 19.499,9.5C19.909,9.5 20.249,9.16 20.249,8.75L20.249,5.75C20.249,5.34 19.909,5 19.499,5ZM19.499,12C19.909,12 20.249,11.66 20.249,11.25C20.249,10.84 19.909,10.5 19.499,10.5C19.089,10.5 18.749,10.84 18.749,11.25C18.749,11.66 19.089,12 19.499,12Z" />
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml
index b699203dd652..e7ebf6f6883a 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2023 The Android Open Source Project
+ Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,22 +14,22 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="14dp"
- android:height="14dp"
- android:viewportWidth="14.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
<path
- android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
- android:fillAlpha="0.24"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
android:fillColor="#000"/>
<path
- android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
- android:fillAlpha="0.24"
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
android:fillColor="#000"/>
<path
- android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml
index ba8649b23b38..49ae9e4ef17f 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml
@@ -1,26 +1,49 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="15dp"
- android:height="14dp"
- android:viewportWidth="15.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
+ <group>
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <clip-path
+ android:pathData="
+ M0,0
+ V13.5,0
+ H13.5,20
+ V0,20
+ H0,0
+ M14.999,13.5C17.761,13.5 19.999,11.261 19.999,8.5C19.999,5.739 17.761,3.5 14.999,3.5C12.238,3.5 9.999,5.739 9.999,8.5C9.999,11.261 12.238,13.5 14.999,13.5Z" />
+ <path
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ </group>
<path
- android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+ android:pathData="M14.999,5C14.589,5 14.249,5.34 14.249,5.75L14.249,8.75C14.249,9.16 14.589,9.5 14.999,9.5C15.409,9.5 15.749,9.16 15.749,8.75L15.749,5.75C15.749,5.34 15.409,5 14.999,5ZM14.999,12C15.409,12 15.749,11.66 15.749,11.25C15.749,10.84 15.409,10.5 14.999,10.5C14.589,10.5 14.249,10.84 14.249,11.25C14.249,11.66 14.589,12 14.999,12Z"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml
index 43fa734c0c8d..19387bc6c75c 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2023 The Android Open Source Project
+ Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,26 +14,26 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="14dp"
- android:viewportWidth="16.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportWidth="20.5"
+ android:viewportHeight="12.0">
<path
- android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
- android:fillAlpha="0.24"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
android:fillColor="#000"/>
<path
- android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
- android:fillAlpha="0.24"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z"
android:fillColor="#000"/>
<path
- android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
- android:fillAlpha="0.24"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml
index 6309e1772d4a..322ede67de5b 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml
@@ -1,30 +1,52 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="14dp"
- android:viewportWidth="18.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportHeight="12.0"
+ android:viewportWidth="20.5">
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <group>
+ <clip-path android:pathData="
+ M0,0
+ H20.5
+ V12.0
+ H0
+ Z
+ M19.499,13.5C22.261,13.5 24.499,11.261 24.499,8.5C24.499,5.739 22.261,3.5 19.499,3.5C16.738,3.5 14.499,5.739 14.499,8.5C14.499,11.261 16.738,13.5 19.499,13.5Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z" />
+ </group>
<path
- android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
- android:fillColor="#000"/>
+ android:fillColor="#000"
+ android:pathData="M19.499,5C19.089,5 18.749,5.34 18.749,5.75L18.749,8.75C18.749,9.16 19.089,9.5 19.499,9.5C19.909,9.5 20.249,9.16 20.249,8.75L20.249,5.75C20.249,5.34 19.909,5 19.499,5ZM19.499,12C19.909,12 20.249,11.66 20.249,11.25C20.249,10.84 19.909,10.5 19.499,10.5C19.089,10.5 18.749,10.84 18.749,11.25C18.749,11.66 19.089,12 19.499,12Z" />
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml
index 6a218b310b3a..b84b6583e8aa 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2023 The Android Open Source Project
+ Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,21 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="14dp"
- android:height="14dp"
- android:viewportWidth="14.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
<path
- android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
android:fillColor="#000"/>
<path
- android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
- android:fillAlpha="0.24"
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
android:fillColor="#000"/>
<path
- android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
android:fillColor="#000"/>
<path
- android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml
index 27433c79e8bb..7c4c1c6b1126 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml
@@ -1,25 +1,48 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="15dp"
- android:height="14dp"
- android:viewportWidth="15.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
+ <group>
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <clip-path
+ android:pathData="
+ M0,0
+ V13.5,0
+ H13.5,20
+ V0,20
+ H0,0
+ M14.999,13.5C17.761,13.5 19.999,11.261 19.999,8.5C19.999,5.739 17.761,3.5 14.999,3.5C12.238,3.5 9.999,5.739 9.999,8.5C9.999,11.261 12.238,13.5 14.999,13.5Z" />
+ <path
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
+ android:fillAlpha="0.45"
+ android:fillColor="#000"/>
+ </group>
<path
- android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+ android:pathData="M14.999,5C14.589,5 14.249,5.34 14.249,5.75L14.249,8.75C14.249,9.16 14.589,9.5 14.999,9.5C15.409,9.5 15.749,9.16 15.749,8.75L15.749,5.75C15.749,5.34 15.409,5 14.999,5ZM14.999,12C15.409,12 15.749,11.66 15.749,11.25C15.749,10.84 15.409,10.5 14.999,10.5C14.589,10.5 14.249,10.84 14.249,11.25C14.249,11.66 14.589,12 14.999,12Z"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml
index 158ae016ffb5..973032f3c237 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2023 The Android Open Source Project
+ Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,25 +14,25 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="14dp"
- android:viewportWidth="16.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportWidth="20.5"
+ android:viewportHeight="12.0">
<path
- android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
android:fillColor="#000"/>
<path
- android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
- android:fillAlpha="0.24"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z"
android:fillColor="#000"/>
<path
- android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z"
android:fillColor="#000"/>
<path
- android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
- android:fillAlpha="0.24"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
<path
- android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml
index e0517cfdfeee..25c9520ad011 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml
@@ -1,29 +1,51 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="14dp"
- android:viewportWidth="18.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportHeight="12.0"
+ android:viewportWidth="20.5">
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <group>
+ <clip-path android:pathData="
+ M0,0
+ H20.5
+ V12.0
+ H0
+ Z
+ M19.499,13.5C22.261,13.5 24.499,11.261 24.499,8.5C24.499,5.739 22.261,3.5 19.499,3.5C16.738,3.5 14.499,5.739 14.499,8.5C14.499,11.261 16.738,13.5 19.499,13.5Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z" />
+ </group>
<path
- android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
- android:fillColor="#000"/>
+ android:fillColor="#000"
+ android:pathData="M19.499,5C19.089,5 18.749,5.34 18.749,5.75L18.749,8.75C18.749,9.16 19.089,9.5 19.499,9.5C19.909,9.5 20.249,9.16 20.249,8.75L20.249,5.75C20.249,5.34 19.909,5 19.499,5ZM19.499,12C19.909,12 20.249,11.66 20.249,11.25C20.249,10.84 19.909,10.5 19.499,10.5C19.089,10.5 18.749,10.84 18.749,11.25C18.749,11.66 19.089,12 19.499,12Z" />
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml
index 1ebd3965f36f..fc807fa90b44 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2023 The Android Open Source Project
+ Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,20 +14,20 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="14dp"
- android:height="14dp"
- android:viewportWidth="14.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
<path
- android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
android:fillColor="#000"/>
<path
- android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
android:fillColor="#000"/>
<path
- android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
android:fillColor="#000"/>
<path
- android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml
index 4473c29d0866..d23680d17b9c 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml
@@ -1,24 +1,47 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="15dp"
- android:height="14dp"
- android:viewportWidth="15.0"
- android:viewportHeight="14.0">
+ android:width="17dp"
+ android:height="12dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="12.0">
+ <group>
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <clip-path
+ android:pathData="
+ M0,0
+ V13.5,0
+ H13.5,20
+ V0,20
+ H0,0
+ M14.999,13.5C17.761,13.5 19.999,11.261 19.999,8.5C19.999,5.739 17.761,3.5 14.999,3.5C12.238,3.5 9.999,5.739 9.999,8.5C9.999,11.261 12.238,13.5 14.999,13.5Z" />
+ <path
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M5.749,4.5C6.439,4.5 6.999,5.06 6.999,5.75L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,5.75C4.499,5.06 5.059,4.5 5.749,4.5Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M10.249,2C10.939,2 11.499,2.56 11.499,3.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,3.25C8.999,2.56 9.559,2 10.249,2Z"
+ android:fillColor="#000"/>
+ <path
+ android:pathData="M14.749,0C15.439,0 15.999,0.56 15.999,1.25L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,1.25C13.499,0.56 14.059,0 14.749,0Z"
+ android:fillColor="#000"/>
+ </group>
<path
- android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+ android:pathData="M14.999,5C14.589,5 14.249,5.34 14.249,5.75L14.249,8.75C14.249,9.16 14.589,9.5 14.999,9.5C15.409,9.5 15.749,9.16 15.749,8.75L15.749,5.75C15.749,5.34 15.409,5 14.999,5ZM14.999,12C15.409,12 15.749,11.66 15.749,11.25C15.749,10.84 15.409,10.5 14.999,10.5C14.589,10.5 14.249,10.84 14.249,11.25C14.249,11.66 14.589,12 14.999,12Z"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml
index 1ed6ac86b21a..b1336d70fc39 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2023 The Android Open Source Project
+ Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,24 +14,24 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="14dp"
- android:viewportWidth="16.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportWidth="20.5"
+ android:viewportHeight="12.0">
<path
- android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
android:fillColor="#000"/>
<path
- android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z"
android:fillColor="#000"/>
<path
- android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z"
android:fillColor="#000"/>
<path
- android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
- android:fillAlpha="0.24"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z"
android:fillColor="#000"/>
<path
- android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z"
+ android:fillAlpha="0.45"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml
index 703e3acd5f75..bf62535b9574 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml
@@ -1,28 +1,50 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="14dp"
- android:viewportWidth="18.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportHeight="12.0"
+ android:viewportWidth="20.5">
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <group>
+ <clip-path android:pathData="
+ M0,0
+ H20.5
+ V12.0
+ H0
+ Z
+ M19.499,13.5C22.261,13.5 24.499,11.261 24.499,8.5C24.499,5.739 22.261,3.5 19.499,3.5C16.738,3.5 14.499,5.739 14.499,8.5C14.499,11.261 16.738,13.5 19.499,13.5Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z" />
+ <path
+ android:fillAlpha="0.45"
+ android:fillColor="#000"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z" />
+ </group>
<path
- android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
- android:fillAlpha="0.3"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
- android:fillColor="#000"/>
+ android:fillColor="#000"
+ android:pathData="M19.499,5C19.089,5 18.749,5.34 18.749,5.75L18.749,8.75C18.749,9.16 19.089,9.5 19.499,9.5C19.909,9.5 20.249,9.16 20.249,8.75L20.249,5.75C20.249,5.34 19.909,5 19.499,5ZM19.499,12C19.909,12 20.249,11.66 20.249,11.25C20.249,10.84 19.909,10.5 19.499,10.5C19.089,10.5 18.749,10.84 18.749,11.25C18.749,11.66 19.089,12 19.499,12Z" />
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml
index 420ffb601e8f..fa9bedc021d8 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2023 The Android Open Source Project
+ Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,23 +14,23 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="14dp"
- android:viewportWidth="16.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportWidth="20.5"
+ android:viewportHeight="12.0">
<path
- android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z"
android:fillColor="#000"/>
<path
- android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z"
android:fillColor="#000"/>
<path
- android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z"
android:fillColor="#000"/>
<path
- android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z"
android:fillColor="#000"/>
<path
- android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z"
android:fillColor="#000"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml
index e63ca77e9db1..1728bc78b22b 100644
--- a/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml
+++ b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml
@@ -1,27 +1,49 @@
+<!--
+ Copyright (C) 2025 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.
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="14dp"
- android:viewportWidth="18.0"
- android:viewportHeight="14.0">
+ android:width="21dp"
+ android:height="12dp"
+ android:viewportHeight="12.0"
+ android:viewportWidth="20.5">
+ <!-- clip-out the circle which will contain the exclamation point (below this group) -->
+ <group>
+ <clip-path android:pathData="
+ M0,0
+ H20.5
+ V12.0
+ H0
+ Z
+ M19.499,13.5C22.261,13.5 24.499,11.261 24.499,8.5C24.499,5.739 22.261,3.5 19.499,3.5C16.738,3.5 14.499,5.739 14.499,8.5C14.499,11.261 16.738,13.5 19.499,13.5Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M5.749,5C6.439,5 6.999,5.56 6.999,6.25L6.999,10.75C6.999,11.44 6.439,12 5.749,12C5.059,12 4.499,11.44 4.499,10.75L4.499,6.25C4.499,5.56 5.059,5 5.749,5Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M10.249,3C10.939,3 11.499,3.56 11.499,4.25L11.499,10.75C11.499,11.44 10.939,12 10.249,12C9.559,12 8.999,11.44 8.999,10.75L8.999,4.25C8.999,3.56 9.559,3 10.249,3Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M14.749,1.5C15.439,1.5 15.999,2.06 15.999,2.75L15.999,10.75C15.999,11.44 15.439,12 14.749,12C14.059,12 13.499,11.44 13.499,10.75L13.499,2.75C13.499,2.06 14.059,1.5 14.749,1.5Z" />
+ <path
+ android:fillColor="#000"
+ android:pathData="M19.249,0C19.939,0 20.499,0.56 20.499,1.25L20.499,10.75C20.499,11.44 19.939,12 19.249,12C18.559,12 17.999,11.44 17.999,10.75L17.999,1.25C17.999,0.56 18.559,0 19.249,0Z" />
+ </group>
<path
- android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
- android:fillColor="#000"/>
- <path
- android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
- android:fillColor="#000"/>
+ android:fillColor="#000"
+ android:pathData="M19.499,5C19.089,5 18.749,5.34 18.749,5.75L18.749,8.75C18.749,9.16 19.089,9.5 19.499,9.5C19.909,9.5 20.249,9.16 20.249,8.75L20.249,5.75C20.249,5.34 19.909,5 19.499,5ZM19.499,12C19.909,12 20.249,11.66 20.249,11.25C20.249,10.84 19.909,10.5 19.499,10.5C19.089,10.5 18.749,10.84 18.749,11.25C18.749,11.66 19.089,12 19.499,12Z" />
</vector>
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index e4eb72d0bf82..c4ba7eb03ae8 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Slegs toestelskerm (verstek)"</item>
- <item msgid="9161645858025071955">"Eksterne skerm"</item>
- <item msgid="114384731934682483">"Fokusgebaseer"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Wys skakering net op toestelskerm"</item>
- <item msgid="7795034287069726554">"Wys skerm op enkele eksterne skerm"</item>
- <item msgid="5280431949814340475">"Wys toestel op laaste gefokusde skerm"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index f6364ffb9116..3a7e45209562 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Laai vinnig"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Beheer deur administrateur"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Beheer deur Beperkte Instellings"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Onbeskikbaar tydens oproepe"</string>
<string name="disabled" msgid="8017887509554714950">"Gedeaktiveer"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Toegelaat"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Nie toegelaat nie"</string>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index 805f0d3c9189..a151f837a8a4 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"የመሣሪያ ማሳያ ብቻ (ነባሪ)"</item>
- <item msgid="9161645858025071955">"ውጫዊ ማሳያ"</item>
- <item msgid="114384731934682483">"ትኩረት ላይ የተመሰረተ"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"በመሣሪያ ማሳያ ላይ ብቻ ጥላ አሳይ"</item>
- <item msgid="7795034287069726554">"መሣሪያን በአንድ ውጫዊ ማሳያ ላይ አሳይ"</item>
- <item msgid="5280431949814340475">"በመጨረሻ ትኩረት የተደረገበት ማሳያ ላይ መሣሪያን አሳይ"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index d374a9a10b3e..25e9c5e3b2a9 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"ፈጣን መሙያ"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"በአስተዳዳሪ ቁጥጥር የተደረገበት"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"በተገደበ ቅንብር ቁጥጥር የሚደረግበት"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"በጥሪዎች ጊዜ አይገኝም"</string>
<string name="disabled" msgid="8017887509554714950">"ቦዝኗል"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"ይፈቀዳል"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"አይፈቀድም"</string>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 3ff5dc642be8..ebdb0c70cd3f 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"شاشة الجهاز فقط (الإعداد التلقائي)"</item>
- <item msgid="9161645858025071955">"الشاشة الخارجية"</item>
- <item msgid="114384731934682483">"على الشاشة التي يتم التركيز عليها"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"عرض الظل على شاشة الجهاز فقط"</item>
- <item msgid="7795034287069726554">"عرض الظل على شاشة خارجية واحدة"</item>
- <item msgid="5280431949814340475">"عرض الظل على آخر شاشة تم التركيز عليها"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 675a6a6077ba..8956c44ec09e 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -251,7 +251,7 @@
<string name="enable_adb_summary" msgid="3711526030096574316">"‏وضع تصحيح الأخطاء عند توصيل USB"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"‏إلغاء عمليات تفويض تصحيح أخطاء USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"تصحيح الأخطاء اللاسلكي"</string>
- <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"‏وضع تصحيح الأخطاء عندما يتم الاتصال بشبكة Wi‑Fi"</string>
+ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"‏بدء تصحيح الأخطاء عند الاتصال بشبكة Wi‑Fi"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"خطأ"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"تصحيح الأخطاء اللاسلكي"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"لعرض الأجهزة المتاحة واستخدامها، فعِّل ميزة \"تصحيح الأخطاء اللاسلكي\"."</string>
@@ -674,7 +674,7 @@
<string name="not_grant_admin" msgid="3557849576157702485">"لا أريد منح هذا المستخدم امتيازات المشرف."</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"خروج"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"هل تريد حفظ النشاط في وضع الضيف؟"</string>
- <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"يمكنك حفظ نشاط من الجلسة الحالية أو حذف كلّ التطبيقات والبيانات."</string>
+ <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"يمكنك حفظ نشاطك من الجلسة الحالية أو حذف كلّ التطبيقات والبيانات."</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"حذف"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"حِفظ"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"الخروج من وضع الضيف"</string>
diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml
index 4b5d5a07e120..451b47ab352f 100644
--- a/packages/SettingsLib/res/values-as/arrays.xml
+++ b/packages/SettingsLib/res/values-as/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"কেৱল ডিভাইচৰ ডিছপ্লে’ (ডিফ’ল্ট)"</item>
<item msgid="9161645858025071955">"বাহ্যিক ডিছপ্লে’"</item>
- <item msgid="114384731934682483">"ফ’কাছ-আধাৰিত"</item>
+ <item msgid="23651860565814477">"শেহতীয়া স্থিতি দণ্ড স্পৰ্শ"</item>
+ <item msgid="7521112827893653392">"ফ’কাছ-আধাৰিত"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"কেৱল ডিভাইচৰ ডিছপ্লে’তহে শ্বেড দেখুৱাওক"</item>
- <item msgid="7795034287069726554">"ডিভাইচটো এখনেই বাহ্যিক ডিছপ্লে’ত দেখুৱাওক"</item>
- <item msgid="5280431949814340475">"ডিভাইচটো অন্তিম ফ’কাছ কৰা ডিছপ্লে’ত দেখুৱাওক"</item>
+ <item msgid="1955398604822147783">"কেৱল এখনেই বাহ্যিক ডিছপ্লে’ত শ্বেড দেখুৱাওক"</item>
+ <item msgid="391477482416751568">"যিখন ডিছপ্লে’ই অন্তিমবাৰ ইয়াৰ স্থিতি দণ্ডৰ সৈতে ভাৱ-বিনিময় কৰিছে সেইখনত শ্বেড দেখুৱাওক"</item>
+ <item msgid="1746820128097981528">"অন্তিম ফ’কাছ কৰা ডিছপ্লে’ত শ্বেড দেখুৱাওক"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index c98d3dec33f1..bfacbb248c0e 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"দ্ৰুত চাৰ্জিং"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"এডমিনৰ দ্বাৰা নিয়ন্ত্ৰিত"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"প্ৰতিবন্ধিত ছেটিঙৰ দ্বাৰা নিয়ন্ত্ৰিত"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"কল চলি থকাৰ সময়ত উপলব্ধ নহয়"</string>
<string name="disabled" msgid="8017887509554714950">"নিষ্ক্ৰিয়"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"অনুমতি দিয়া হৈছে"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"অনুমতি দিয়া হোৱা নাই"</string>
diff --git a/packages/SettingsLib/res/values-az/arrays.xml b/packages/SettingsLib/res/values-az/arrays.xml
index 511e9701cd71..52cf498e00ab 100644
--- a/packages/SettingsLib/res/values-az/arrays.xml
+++ b/packages/SettingsLib/res/values-az/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Yalnız cihaz displeyi (defolt)"</item>
- <item msgid="9161645858025071955">"Xarici displey"</item>
- <item msgid="114384731934682483">"Fokus əsaslı"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Kölgəni yalnız cihaz displeyində göstərin"</item>
- <item msgid="7795034287069726554">"Cihazı bir xarici displeydə göstərin"</item>
- <item msgid="5280431949814340475">"Cihazı son fokuslanmış displeydə göstərin"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index db7d162b9ccd..9013fb5bc324 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Sürətli şarj"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Admin tərəfindən nəzarət olunur"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Məhdudlaşdırılmış Ayar ilə nəzarət edilir"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Zənglər zamanı əlçatan deyil"</string>
<string name="disabled" msgid="8017887509554714950">"Deaktiv"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"İcazə verilib"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"İcazə verilməyib"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
index 452831453acf..3622808a3318 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Prikaz samo na uređaju (podrazumevano)"</item>
<item msgid="9161645858025071955">"Spoljni ekran"</item>
- <item msgid="114384731934682483">"Zasnovano na fokusu"</item>
+ <item msgid="23651860565814477">"Dodir na najnovijoj statusnoj traci"</item>
+ <item msgid="7521112827893653392">"Zasnovano na fokusu"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Prikaži senku samo na ekranu uređaja"</item>
- <item msgid="7795034287069726554">"Prikaži uređaj na jednom spoljnom ekranu"</item>
- <item msgid="5280431949814340475">"Prikaži uređaj na poslednjem ekranu u fokusu"</item>
+ <item msgid="1955398604822147783">"Prikaži senku na jednom spoljnom ekranu"</item>
+ <item msgid="391477482416751568">"Prikaži senku na ekranu sa kojim je statusna traka poslednji put bila u interakciji"</item>
+ <item msgid="1746820128097981528">"Prikaži senku na poslednjem ekranu u fokusu"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-be/arrays.xml b/packages/SettingsLib/res/values-be/arrays.xml
index 33393610fae2..48c362768a8f 100644
--- a/packages/SettingsLib/res/values-be/arrays.xml
+++ b/packages/SettingsLib/res/values-be/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Толькі дысплэй прылады (стандартна)"</item>
- <item msgid="9161645858025071955">"Знешні дысплэй"</item>
- <item msgid="114384731934682483">"У залежнасці ад выкарыстання"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Паказваць шчыток толькі на дысплэі прылады"</item>
- <item msgid="7795034287069726554">"Паказваць прыладу на адным знешнім дысплэі"</item>
- <item msgid="5280431949814340475">"Паказваць прыладу на дысплэі, які выкарыстоўваўся апошнім"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index eb6e0a559ce4..0ad8ac7502b0 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Ідзе хуткая зарадка"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Кантралюецца адміністратарам"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Пад кіраваннем Абмежаванага наладжвання"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Недаступна падчас выклікаў"</string>
<string name="disabled" msgid="8017887509554714950">"Адключанае"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Дазволена"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Забаронена"</string>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index c3bc26f30dbf..21dfa06644a3 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Само на екрана на устройството (по подразбиране)"</item>
- <item msgid="9161645858025071955">"Външен екран"</item>
- <item msgid="114384731934682483">"Въз основа на фокуса"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Показване на падащия панел само на екрана на устройството"</item>
- <item msgid="7795034287069726554">"Показване на устройството на един външен екран"</item>
- <item msgid="5280431949814340475">"Показване на устройството на екрана, върху който последно е бил поставен фокусът"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index ede0a3a69a1a..8a87e57ffe93 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Зарежда се бързо"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролира се от администратор"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Управлява се чрез ограничена настройка"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Заето по време на обаждания"</string>
<string name="disabled" msgid="8017887509554714950">"Деактивирано"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Има разрешение"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Няма разрешение"</string>
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index 6d5da27f3c36..b27264d5541b 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"শুধুমাত্র ডিভাইসের ডিসপ্লে (ডিফল্ট)"</item>
- <item msgid="9161645858025071955">"এক্সটার্নাল ডিসপ্লে"</item>
- <item msgid="114384731934682483">"ফোকাস অনুযায়ী"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"শুধুমাত্র ডিভাইসের ডিসপ্লেতে শেড দেখুন"</item>
- <item msgid="7795034287069726554">"শেড একটি এক্সটার্নাল ডিসপ্লেতে দেখুন"</item>
- <item msgid="5280431949814340475">"ফোকাস করা শেষ ডিসপ্লেতে ডিভাইস দেখুন"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index ab9c34ac6f73..1e7c7a227b8e 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"ফাস্ট চার্জিং"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"প্রশাসকের দ্বারা নিয়ন্ত্রিত"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"এটি বিধিনিষেধ সেটিং থেকে নিয়ন্ত্রণ করা হয়"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"কল চলাকালীন উপলভ্য হবে না"</string>
<string name="disabled" msgid="8017887509554714950">"অক্ষম হয়েছে"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"অনুমোদিত"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"অনুমোদিত নয়"</string>
diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml
index 625112ce873d..44bbfaf4d56e 100644
--- a/packages/SettingsLib/res/values-bs/arrays.xml
+++ b/packages/SettingsLib/res/values-bs/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Samo zaslon uređaja (zadano)"</item>
<item msgid="9161645858025071955">"Vanjski ekran"</item>
- <item msgid="114384731934682483">"Na osnovu fokusa"</item>
+ <item msgid="23651860565814477">"Najnoviji dodir trake statusa"</item>
+ <item msgid="7521112827893653392">"Na temelju fokusa"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Prikaži sjenu samo na ekranu uređaja"</item>
- <item msgid="7795034287069726554">"Prikaži uređaj na jednom vanjskom ekranu"</item>
- <item msgid="5280431949814340475">"Prikaži uređaj na posljednjem fokusiranom ekranu"</item>
+ <item msgid="1955398604822147783">"Prikaži sjenčanje na jednom vanjskom zaslonu"</item>
+ <item msgid="391477482416751568">"Prikaži sjenčanje na zaslonu na kojem je posljednje stupljeno u interakciju s trakom statusa"</item>
+ <item msgid="1746820128097981528">"Prikaži sjenčanje na posljednjem fokusiranom zaslonu"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 98e07b9e8749..756a3268ec98 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -482,7 +482,7 @@
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je na čekanju radi zaštite baterije"</string>
- <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjerite opremu za punjenje"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjerite dodatak za punjenje"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> na osnovu vaše potrošnje"</string>
@@ -523,7 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Brzo punjenje"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Pod kontrolom administratora"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolira ograničena postavka"</string>
- <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nije dostupno tijekom poziva"</string>
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nije dostupno tokom poziva"</string>
<string name="disabled" msgid="8017887509554714950">"Onemogućeno"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Dozvoljeno"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Nije dozvoljeno"</string>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index e9b437e717d9..f19551c5194b 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Només a la pantalla del dispositiu (opció predeterminada)"</item>
- <item msgid="9161645858025071955">"Pantalla externa"</item>
- <item msgid="114384731934682483">"Basat en l\'enfocament"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Mostra l\'ombra només a la pantalla del dispositiu"</item>
- <item msgid="7795034287069726554">"Mostra el dispositiu en una sola pantalla externa"</item>
- <item msgid="5280431949814340475">"Mostra el dispositiu a la darrera pantalla en què s\'hagi posat el focus"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index ef2920d2a28e..05480999b3e0 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Càrrega ràpida"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlat per l\'administrador"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlat per l\'opció de configuració restringida"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"No està disponible durant les trucades"</string>
<string name="disabled" msgid="8017887509554714950">"Desactivat"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Amb permís"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Sense permís"</string>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index 4bfdaf47ea9b..ad1cafd2dd2d 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Pouze zobrazení zařízení (výchozí)"</item>
- <item msgid="9161645858025071955">"Externí displej"</item>
- <item msgid="114384731934682483">"Výběr"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Zobrazovat panel pouze na displeji zařízení"</item>
- <item msgid="7795034287069726554">"Zobrazovat panel na jednom externím displeji"</item>
- <item msgid="5280431949814340475">"Zobrazovat panel na naposledy vybraném displeji"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 69497555fae7..ed457756abfa 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Kun på enhedens skærm (standard)"</item>
- <item msgid="9161645858025071955">"Ekstern skærm"</item>
- <item msgid="114384731934682483">"Fokusbaseret"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Vis kun skygge på enhedens skærm"</item>
- <item msgid="7795034287069726554">"Vis enheden på en enkelt ekstern skærm"</item>
- <item msgid="5280431949814340475">"Vis enheden på den skærm, der sidst var i fokus"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 71c6be17eb94..d7aa9b1dd71a 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Lynopladning"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolleret af administratoren"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Styres af en begrænset indstilling"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Kan ikke bruges under opkald"</string>
<string name="disabled" msgid="8017887509554714950">"Deaktiveret"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Tilladt"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Ikke tilladt"</string>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index adddd7706617..924718a37a4d 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Nur Gerätedisplay (Standard)"</item>
- <item msgid="9161645858025071955">"Externes Display"</item>
- <item msgid="114384731934682483">"Fokusbasiert"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Leiste nur auf dem Display des Geräts anzeigen"</item>
- <item msgid="7795034287069726554">"Gerät auf einem einzigen externen Display anzeigen"</item>
- <item msgid="5280431949814340475">"Gerät auf zuletzt fokussiertem Display anzeigen"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 1955da0b80e0..73268c5aa6b2 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -56,7 +56,7 @@
<string name="wifi_disabled_password_failure" msgid="6892387079613226738">"Authentifizierungsproblem"</string>
<string name="wifi_cant_connect" msgid="5718417542623056783">"Verbindung nicht möglich"</string>
<string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"Keine Verbindung zu \"<xliff:g id="AP_NAME">%1$s</xliff:g>\" möglich"</string>
- <string name="wifi_check_password_try_again" msgid="8817789642851605628">"Prüfe das Passwort und versuch es noch einmal"</string>
+ <string name="wifi_check_password_try_again" msgid="8817789642851605628">"Prüfe das Passwort und versuche es noch einmal"</string>
<string name="wifi_not_in_range" msgid="1541760821805777772">"Nicht in Reichweite"</string>
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Kein automatischer Verbindungsaufbau"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Kein Internetzugriff"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Schnelles Laden"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Durch den Administrator verwaltet"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Gesteuert durch eingeschränkte Einstellung"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Während Anrufen nicht verfügbar"</string>
<string name="disabled" msgid="8017887509554714950">"Deaktiviert"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Zugelassen"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Nicht zugelassen"</string>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index 9d7612ca8df1..41aefc097bcd 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Μόνο οθόνη συσκευής (Προεπιλογή)"</item>
- <item msgid="9161645858025071955">"Εξωτερική οθόνη"</item>
- <item msgid="114384731934682483">"Με εστίαση"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Εμφάνιση σκίασης μόνο στην οθόνη συσκευής"</item>
- <item msgid="7795034287069726554">"Εμφάνιση συσκευής σε μία εξωτερική οθόνη"</item>
- <item msgid="5280431949814340475">"Εμφάνιση συσκευής στην τελευταία οθόνη με εστίαση"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 7f9f646b0eaf..209b7820b59a 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Γρήγορη φόρτιση"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Ελέγχονται από το διαχειριστή"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ελέγχεται από τη Ρύθμιση με περιορισμό"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Μη διαθέσιμη κατά τη διάρκεια κλήσεων"</string>
<string name="disabled" msgid="8017887509554714950">"Απενεργοποιημένη"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Επιτρέπεται"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Δεν επιτρέπεται"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index 8c27ec6315c9..6c7a7ffb58ed 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Device display only (default)"</item>
- <item msgid="9161645858025071955">"External display"</item>
- <item msgid="114384731934682483">"Focus-based"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Show shade on device display only"</item>
- <item msgid="7795034287069726554">"Show device on single external display"</item>
- <item msgid="5280431949814340475">"Show device on last focused display"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 58bb7d8b951a..d965c6522a9d 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Fast charging"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlled by admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Unavailable during calls"</string>
<string name="disabled" msgid="8017887509554714950">"Disabled"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Allowed"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/arrays.xml b/packages/SettingsLib/res/values-en-rCA/arrays.xml
index cfe77ca538bd..48f2f5a2c00f 100644
--- a/packages/SettingsLib/res/values-en-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rCA/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Device display only (Default)"</item>
<item msgid="9161645858025071955">"External display"</item>
- <item msgid="114384731934682483">"Focus-based"</item>
+ <item msgid="23651860565814477">"Latest status bar touch"</item>
+ <item msgid="7521112827893653392">"Focus-based"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Show shade on device display only"</item>
- <item msgid="7795034287069726554">"Show device on single external display"</item>
- <item msgid="5280431949814340475">"Show device on last focused display"</item>
+ <item msgid="1955398604822147783">"Show shade on single external display"</item>
+ <item msgid="391477482416751568">"Show shade on display which last had its status bar interacted with"</item>
+ <item msgid="1746820128097981528">"Show shade on last focused display"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index 8c27ec6315c9..6c7a7ffb58ed 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Device display only (default)"</item>
- <item msgid="9161645858025071955">"External display"</item>
- <item msgid="114384731934682483">"Focus-based"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Show shade on device display only"</item>
- <item msgid="7795034287069726554">"Show device on single external display"</item>
- <item msgid="5280431949814340475">"Show device on last focused display"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 58bb7d8b951a..d965c6522a9d 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Fast charging"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlled by admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Unavailable during calls"</string>
<string name="disabled" msgid="8017887509554714950">"Disabled"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Allowed"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index 8c27ec6315c9..6c7a7ffb58ed 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Device display only (default)"</item>
- <item msgid="9161645858025071955">"External display"</item>
- <item msgid="114384731934682483">"Focus-based"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Show shade on device display only"</item>
- <item msgid="7795034287069726554">"Show device on single external display"</item>
- <item msgid="5280431949814340475">"Show device on last focused display"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 58bb7d8b951a..d965c6522a9d 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Fast charging"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlled by admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Unavailable during calls"</string>
<string name="disabled" msgid="8017887509554714950">"Disabled"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Allowed"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index daf9ab98996d..5894975de1ba 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Solo en la pantalla del dispositivo (predeterminado)"</item>
- <item msgid="9161645858025071955">"Pantalla externa"</item>
- <item msgid="114384731934682483">"Basado en el enfoque"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Mostrar sobra solo en la pantalla del dispositivo"</item>
- <item msgid="7795034287069726554">"Mostrar dispositivo en una sola pantalla externa"</item>
- <item msgid="5280431949814340475">"Mostrar dispositivo en la última pantalla enfocada"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index a4bb49ee145a..1e8c6614280c 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Solo en la pantalla del dispositivo (predeterminado)"</item>
- <item msgid="9161645858025071955">"Pantalla externa"</item>
- <item msgid="114384731934682483">"Basado en el enfoque"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Mostrar el panel solo en la pantalla del dispositivo"</item>
- <item msgid="7795034287069726554">"Mostrar el dispositivo en una sola pantalla externa"</item>
- <item msgid="5280431949814340475">"Mostrar el dispositivo en la última pantalla enfocada"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index b881994d911f..00b987c75602 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Carga rápida"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlada por el administrador"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlado por ajustes restringidos"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"No disponible durante las llamadas"</string>
<string name="disabled" msgid="8017887509554714950">"Inhabilitada"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Autorizadas"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"No autorizadas"</string>
diff --git a/packages/SettingsLib/res/values-et/arrays.xml b/packages/SettingsLib/res/values-et/arrays.xml
index 9a77991309a2..88b8b98cc3dc 100644
--- a/packages/SettingsLib/res/values-et/arrays.xml
+++ b/packages/SettingsLib/res/values-et/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Ainult seadme ekraan (vaikimisi)"</item>
<item msgid="9161645858025071955">"Väline ekraan"</item>
- <item msgid="114384731934682483">"Fookusepõhine"</item>
+ <item msgid="23651860565814477">"Viimane olekuriba puudutus"</item>
+ <item msgid="7521112827893653392">"Fookusepõhine"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Kuva menüü ainult seadme ekraanil"</item>
- <item msgid="7795034287069726554">"Kuva seade ühe välisel ekraanil"</item>
- <item msgid="5280431949814340475">"Kuva seade viimati esile tõstetud ekraanil"</item>
+ <item msgid="1955398604822147783">"Kuva menüü ühel välisel ekraanil"</item>
+ <item msgid="391477482416751568">"Kuva menüü ekraanil, mille olekuriba viimati kasutati"</item>
+ <item msgid="1746820128097981528">"Kuva menüü viimati esile tõstetud ekraanil"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml
index 3d59a279d3c0..a1528c2a1e7d 100644
--- a/packages/SettingsLib/res/values-eu/arrays.xml
+++ b/packages/SettingsLib/res/values-eu/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Gailuaren pantailan soilik (lehenetsia)"</item>
- <item msgid="9161645858025071955">"Kanpoko pantailan"</item>
- <item msgid="114384731934682483">"Fokuaren arabera"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Erakutsi itzalak gailuaren pantailan soilik"</item>
- <item msgid="7795034287069726554">"Erakutsi gailua kanpoko pantaila bakarrean"</item>
- <item msgid="5280431949814340475">"Erakutsi gailua fokuratutako azken pantailan"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index a5235cf5336a..1c422b656347 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Kargatze bizkorra"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Administratzaileak kontrolatzen du"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ezarpen mugatuak kontrolatzen du"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ez dago erabilgarri deiak egin bitartean"</string>
<string name="disabled" msgid="8017887509554714950">"Desgaituta"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Baimenduta"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Baimendu gabe"</string>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index 9e1da41e6edc..d7face8672af 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"۲"</item>
<item msgid="4779928470672877922">"۳"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"فقط نمایشگر دستگاه (پیش‌فرض)"</item>
- <item msgid="9161645858025071955">"نمایشگر خارجی"</item>
- <item msgid="114384731934682483">"کانونی‌محور"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"نمایش سایه فقط در نمایشگر دستگاه"</item>
- <item msgid="7795034287069726554">"نمایش دستگاه در یک نمایشگر خارجی"</item>
- <item msgid="5280431949814340475">"نمایش دستگاه در آخرین نمایشگر کانونی‌شده"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"نمایشگر_پیش‌فرض"</item>
- <item msgid="774789415968826925">"هر_نمایشگر_خارجی"</item>
- <item msgid="7880769915418638436">"آخرین_لمس_نوار_وضعیت"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 6d5e42b976f5..b1f76fb5a787 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"درحال شارژ سریع"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"توسط سرپرست سیستم کنترل می‌شود"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"با تنظیم «حالت محدود» کنترل می‌شود"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"درطول تماس دردسترس نیست"</string>
<string name="disabled" msgid="8017887509554714950">"غیر فعال شد"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"مجاز بودن"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"مجاز نبودن"</string>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index 0c970ec5fbbd..a10dfbe7a2f9 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Vain laitteen näyttö (oletus)"</item>
- <item msgid="9161645858025071955">"Ulkoinen näyttö"</item>
- <item msgid="114384731934682483">"Kohdistusperustainen"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Näytä ilmoitusalue vain laitteen näytöllä"</item>
- <item msgid="7795034287069726554">"Näytä laite yhdellä ulkoisella näytöllä"</item>
- <item msgid="5280431949814340475">"Näytä laite viimeksi kohdistetulla näytöllä"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 1e2db99f14d7..b59aa3019f67 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Nopea lataus"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Järjestelmänvalvoja hallinnoi tätä asetusta."</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Rajoitettujen asetusten mukaisesti"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ei käytettävissä puhelujen aikana"</string>
<string name="disabled" msgid="8017887509554714950">"Pois päältä"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Sallittu"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Ei sallittu"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index 6fc0ed9a1e3c..9eec65d3119c 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Écran de l\'appareil seulement (par défaut)"</item>
- <item msgid="9161645858025071955">"Écran externe"</item>
- <item msgid="114384731934682483">"Affichage mis en évidence"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Afficher le volet sur l\'écran de l\'appareil seulement"</item>
- <item msgid="7795034287069726554">"Afficher l\'appareil sur un seul écran externe"</item>
- <item msgid="5280431949814340475">"Afficher l\'appareil sur le dernier affichage mis en évidence"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index f2a3454268c0..99ba8b0ba5df 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Recharge rapide"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Contrôlé par l\'administrateur"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Contrôlé par les paramètres restreints"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponible pendant les appels"</string>
<string name="disabled" msgid="8017887509554714950">"Désactivée"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Autorisée"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Non autorisée"</string>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index 36eb52d66ef2..37875095b6dc 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Écran de l\'appareil uniquement (par défaut)"</item>
- <item msgid="9161645858025071955">"Écran externe"</item>
- <item msgid="114384731934682483">"Basé sur la sélection"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Afficher le volet sur l\'écran de l\'appareil uniquement"</item>
- <item msgid="7795034287069726554">"Afficher l\'appareil sur un seul écran externe"</item>
- <item msgid="5280431949814340475">"Afficher l\'appareil sur le dernier écran avec lequel l\'utilisateur a interagi"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index a017fa74e658..ba77d87100c2 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Recharge rapide"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Contrôlé par l\'administrateur"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Contrôlé par les paramètres restreints"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponible pendant les appels"</string>
<string name="disabled" msgid="8017887509554714950">"Désactivée"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Autorisé"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Non autorisé"</string>
diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml
index cd085fa65275..9307ba7e747a 100644
--- a/packages/SettingsLib/res/values-gl/arrays.xml
+++ b/packages/SettingsLib/res/values-gl/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Só pantalla do dispositivo (opción predeterminada)"</item>
- <item msgid="9161645858025071955">"Pantalla externa"</item>
- <item msgid="114384731934682483">"En función do enfoque"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Mostrar panel despregable só na pantalla do dispositivo"</item>
- <item msgid="7795034287069726554">"Mostrar dispositivo nunha única pantalla externa"</item>
- <item msgid="5280431949814340475">"Mostrar dispositivo na última pantalla enfocada"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"pantalla_predeterminada"</item>
- <item msgid="774789415968826925">"calquera_pantalla_externa"</item>
- <item msgid="7880769915418638436">"último_toque_barra_estado"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 6b2801938173..3d5a9bdfedae 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Carga rápida"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Opción controlada polo administrador"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Baixo o control de opcións restrinxidas"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Non dispoñible durante as chamadas"</string>
<string name="disabled" msgid="8017887509554714950">"Desactivada"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Permiso concedido"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Permiso non concedido"</string>
diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml
index 912df2d85988..6026663ba4df 100644
--- a/packages/SettingsLib/res/values-gu/arrays.xml
+++ b/packages/SettingsLib/res/values-gu/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"માત્ર ડિવાઇસનું ડિસ્પ્લે (ડિફૉલ્ટ)"</item>
- <item msgid="9161645858025071955">"બાહ્ય ડિસ્પ્લે"</item>
- <item msgid="114384731934682483">"ફોકસ-આધારિત"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"માત્ર ડિવાઇસના ડિસ્પ્લે પર શેડ બતાવો"</item>
- <item msgid="7795034287069726554">"માત્ર એક બાહ્ય ડિસ્પ્લે પર ડિવાઇસ બતાવો"</item>
- <item msgid="5280431949814340475">"છેલ્લે ફોકસ કરેલા ડિસ્પ્લે પર ડિવાઇસ બતાવો"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index fbf9afc0a8a4..57ecad80e7e9 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -107,7 +107,7 @@
<string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"જમણી બાજુ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"સક્રિય"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"સાચવેલું"</string>
- <string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"ચાલુ છે (માત્ર ડાબી બાજુ)"</string>
+ <string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"સક્રિય (માત્ર ડાબી બાજુ)"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="2244728507170385397">"ચાલુ છે (માત્ર જમણી બાજુ)"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="4294571497939983181">"ચાલુ છે (ડાબી અને જમણી બાજુ)"</string>
<string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"આસપાસના અવાજો અપડેટ કરી શક્યા નથી"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"ઝડપી ચાર્જિંગ"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"વ્યવસ્થાપક દ્વારા નિયંત્રિત"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"પ્રતિબંધિત સેટિંગ દ્વારા નિયંત્રિત"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"કૉલ દરમિયાન અનુપલબ્ધ"</string>
<string name="disabled" msgid="8017887509554714950">"બંધ કરી"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"મંજૂરી છે"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"મંજૂરી નથી"</string>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 25d638897f96..67de2aea289a 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"सिर्फ़ डिवाइस का डिसप्ले (डिफ़ॉल्ट)"</item>
- <item msgid="9161645858025071955">"बाहरी डिसप्ले पर"</item>
- <item msgid="114384731934682483">"फ़ोकस के हिसाब से"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"सिर्फ़ डिवाइस के डिसप्ले पर शेड दिखाएं"</item>
- <item msgid="7795034287069726554">"शेड को बाहरी डिसप्ले पर दिखाएं"</item>
- <item msgid="5280431949814340475">"फ़ोकस किए गए पिछले डिसप्ले पर शेड दिखाएं"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index e883615477fe..c1f4fe25f4aa 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -107,7 +107,7 @@
<string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"दाएं ईयरबड में <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी बची है"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"चालू"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"सेव किया गया"</string>
- <string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"सिर्फ़ बाईं तरफ़ वाला चालू है"</string>
+ <string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"सिर्फ़ बाईं ओर की मशीन चालू है"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="2244728507170385397">"सिर्फ़ दाईं तरफ़ वाला चालू है"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="4294571497939983181">"बाईं और दाईं तरफ़ वाला चालू है"</string>
<string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"वॉल्यूम को मैनेज करने की सेटिंग नहीं बदली जा सकी"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"फ़ास्ट चार्जिंग"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"इसका नियंत्रण एडमिन के पास है"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"इसे पाबंदी मोड वाली सेटिंग से कंट्रोल किया जाता है"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"कॉल के दौरान उपलब्ध नहीं है"</string>
<string name="disabled" msgid="8017887509554714950">"बंद किया गया"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"अनुमति है"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"अनुमति नहीं है"</string>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index 639e39ec1410..d0ab9fd45fa7 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Samo zaslon uređaja (zadano)"</item>
<item msgid="9161645858025071955">"Vanjski zaslon"</item>
- <item msgid="114384731934682483">"Na temelju fokusa"</item>
+ <item msgid="23651860565814477">"Najnoviji dodir trake statusa"</item>
+ <item msgid="7521112827893653392">"Na temelju fokusa"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Prikaži sjenu samo na zaslonu uređaja"</item>
- <item msgid="7795034287069726554">"Prikaži uređaj na jednom vanjskom zaslonu"</item>
- <item msgid="5280431949814340475">"Prikaži uređaj na posljednjem fokusiranom zaslonu"</item>
+ <item msgid="1955398604822147783">"Prikaži sjenčanje na jednom vanjskom zaslonu"</item>
+ <item msgid="391477482416751568">"Prikaži sjenčanje na zaslonu na kojem je posljednje stupljeno u interakciju s trakom statusa"</item>
+ <item msgid="1746820128097981528">"Prikaži sjenčanje na posljednjem fokusiranom zaslonu"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index d1319665bf0b..d8d42f952734 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Csak az eszköz kijelzője (alapértelmezett)"</item>
- <item msgid="9161645858025071955">"Külső kijelző"</item>
- <item msgid="114384731934682483">"Fókusz alapján"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Felület megjelenítése csak az eszköz kijelzőjén"</item>
- <item msgid="7795034287069726554">"Felület megjelenítése egyetlen külső kijelzőn"</item>
- <item msgid="5280431949814340475">"Felület megjelenítése a legutóbb fókuszban lévő kijelzőn"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 6627cb140777..fa321555075f 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Gyors töltés…"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Rendszergazda által irányítva"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Korlátozott beállítás vezérli"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nem áll rendelkezésre hívások közben"</string>
<string name="disabled" msgid="8017887509554714950">"Letiltva"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Engedélyezett"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Nem engedélyezett"</string>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index 56545014e60f..b2133fbafb26 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Միայն սարքի էկրանը (կանխադրված)"</item>
- <item msgid="9161645858025071955">"Արտաքին էկրան"</item>
- <item msgid="114384731934682483">"Ֆոկուսի հիման վրա"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Ցույց տալ երանգը միայն սարքի էկրանին"</item>
- <item msgid="7795034287069726554">"Ցույց տալ սարքը մեկ արտաքին էկրանին"</item>
- <item msgid="5280431949814340475">"Ցույց տալ սարքը վերջին ֆոկուսավորված էկրանին"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 2248b7bd59f0..fa87813cc122 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Արագ լիցքավորում"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Վերահսկվում է ադմինիստրատորի կողմից"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Կառավարվում է սահմանափակ ռեժիմի կարգավորումներով"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Զանգի ընթացքում հասանելի չէ"</string>
<string name="disabled" msgid="8017887509554714950">"Կասեցված է"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Թույլատրված է"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Արգելված"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index c256e8cd72d0..fa2fa9e3d56c 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Hanya layar perangkat (Default)"</item>
- <item msgid="9161645858025071955">"Layar eksternal"</item>
- <item msgid="114384731934682483">"Berbasis fokus"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Tampilkan shade hanya di layar perangkat"</item>
- <item msgid="7795034287069726554">"Tampilkan perangkat di satu layar eksternal"</item>
- <item msgid="5280431949814340475">"Tampilkan perangkat di layar yang terakhir difokuskan"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 5798f8d4931b..1ff4b29ddaa0 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Pengisian daya cepat"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Dikontrol oleh admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Dikontrol oleh Setelan Terbatas"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Tidak tersedia selama panggilan berlangsung"</string>
<string name="disabled" msgid="8017887509554714950">"Dinonaktifkan"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Diizinkan"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Tidak diizinkan"</string>
diff --git a/packages/SettingsLib/res/values-is/arrays.xml b/packages/SettingsLib/res/values-is/arrays.xml
index 1d81344ba7b2..851a7a4929ea 100644
--- a/packages/SettingsLib/res/values-is/arrays.xml
+++ b/packages/SettingsLib/res/values-is/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Aðeins skjár tækis (sjálfgefið)"</item>
- <item msgid="9161645858025071955">"Ytri skjár"</item>
- <item msgid="114384731934682483">"Byggt á fókus"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Aðeins skyggja skjá tækis"</item>
- <item msgid="7795034287069726554">"Sýna tæki á einum ytri skjá"</item>
- <item msgid="5280431949814340475">"Sýna tæki á skjá sem var síðast í fókus"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index e8e49d072ef7..804ea6318400 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Hraðhleðsla"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Stjórnað af kerfisstjóra"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Stýrt af takmarkaði stillingu"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ekki í boði á meðan á símtölum stendur"</string>
<string name="disabled" msgid="8017887509554714950">"Óvirkt"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Heimilað"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Ekki heimilað"</string>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index 331410cada30..48777a398b83 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Solo display del dispositivo (impostazione predefinita)"</item>
<item msgid="9161645858025071955">"Display esterno"</item>
- <item msgid="114384731934682483">"In base alla selezione"</item>
+ <item msgid="23651860565814477">"Ultimo tocco alla barra di stato"</item>
+ <item msgid="7521112827893653392">"In base alla selezione"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Mostra l\'area delle notifiche solo sul display del dispositivo"</item>
- <item msgid="7795034287069726554">"Mostra il dispositivo su un singolo display esterno"</item>
- <item msgid="5280431949814340475">"Mostra il dispositivo sull\'ultimo display selezionato"</item>
+ <item msgid="1955398604822147783">"Mostra l\'area delle notifiche su un singolo display esterno"</item>
+ <item msgid="391477482416751568">"Mostra l\'area delle notifiche sul display in cui è avvenuta l\'ultima interazione con la barra di stato"</item>
+ <item msgid="1746820128097981528">"Mostra l\'area delle notifiche sull\'ultimo display selezionato"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index b2404cf7a305..09ec5ccaf23f 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -107,7 +107,7 @@
<string name="tv_bluetooth_battery_level_untethered_right" msgid="8610019317279155595">"Destra: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Attivo"</string>
<string name="bluetooth_saved_device" msgid="4895871321722311428">"Dispositivo salvato"</string>
- <string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Attivo (solo sinistro)"</string>
+ <string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Attiva (solo sinistra)"</string>
<string name="bluetooth_hearing_aid_right_active" msgid="2244728507170385397">"Attivo (solo destro)"</string>
<string name="bluetooth_hearing_aid_left_and_right_active" msgid="4294571497939983181">"Attivi (destro e sinistro)"</string>
<string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Impossibile aggiornare audio ambientale"</string>
@@ -505,8 +505,8 @@
<string name="power_charging_limited" msgid="4144004473976005214">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica in sospeso per proteggere la batteria"</string>
<string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ In carica"</string>
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Ricarica completa entro <xliff:g id="TIME">%3$s</xliff:g>"</string>
- <string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batteria completamente carica entro <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Batteria completamente carica entro <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batteria completamente carica entro: <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Batteria completamente carica entro: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Ricarica completa entro le ore <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Sconosciuta"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"In carica"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Ricarica rapida"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Gestita dall\'amministratore"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Gestita tramite impostazioni con restrizioni"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Non disponibile durante le chiamate"</string>
<string name="disabled" msgid="8017887509554714950">"Disattivato"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Autorizzazione concessa"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Autorizzazione non concessa"</string>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 5c1845f6dca9..9d176c03cdfb 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"מסך המכשיר בלבד (ברירת המחדל)"</item>
- <item msgid="9161645858025071955">"מסך חיצוני"</item>
- <item msgid="114384731934682483">"לפי התמקדות"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"הצגת הצללה במסך המכשיר בלבד"</item>
- <item msgid="7795034287069726554">"הצגת המכשיר במסך חיצוני אחד"</item>
- <item msgid="5280431949814340475">"הצגת ההתראות במסך האחרון שהשתמשת בו"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index b5201058a439..361dd1804e0b 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"טעינה מהירה"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"נמצא בשליטת מנהל מערכת"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"בשליטה של הגדרה מוגבלת"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ההעדפה הזו לא זמינה במהלך שיחות"</string>
<string name="disabled" msgid="8017887509554714950">"מושבת"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"מורשה"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"לא מורשה"</string>
@@ -617,7 +616,7 @@
<string name="help_label" msgid="3528360748637781274">"עזרה ומשוב"</string>
<string name="storage_category" msgid="2287342585424631813">"אחסון"</string>
<string name="shared_data_title" msgid="1017034836800864953">"נתונים משותפים"</string>
- <string name="shared_data_summary" msgid="5516326713822885652">"הצגה ושינוי של נתונים משותפים"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"צפייה בנתונים המשותפים ושינוי שלהם"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"אין נתונים משותפים למשתמש הזה."</string>
<string name="shared_data_query_failure_text" msgid="3489828881998773687">"אירעה שגיאה באחזור הנתונים המשותפים. צריך לנסות שוב."</string>
<string name="blob_id_text" msgid="8680078988996308061">"מזהה נתונים משותפים: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index 9dc234b8758d..d5d5ff1330ef 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"デバイスのディスプレイのみ(デフォルト)"</item>
<item msgid="9161645858025071955">"外部ディスプレイ"</item>
- <item msgid="114384731934682483">"フォーカスに基づく"</item>
+ <item msgid="23651860565814477">"ステータスバーの最新のタップ"</item>
+ <item msgid="7521112827893653392">"フォーカスに基づく"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"デバイスのディスプレイにのみシェードを表示する"</item>
- <item msgid="7795034287069726554">"1 台の外部ディスプレイにデバイスを表示する"</item>
- <item msgid="5280431949814340475">"最後にフォーカスされたディスプレイにデバイスを表示する"</item>
+ <item msgid="1955398604822147783">"1 台の外部ディスプレイにシェードを表示する"</item>
+ <item msgid="391477482416751568">"最後にステータスバーが操作されたディスプレイにシェードを表示する"</item>
+ <item msgid="1746820128097981528">"最後にフォーカスされたディスプレイにシェードを表示する"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 320c707a92a0..1170cd1db76a 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -123,7 +123,7 @@
<string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"有効(メディアのみ)、左のみ"</string>
<string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"有効(メディアのみ)、右のみ"</string>
<string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"有効(メディアのみ)、左右"</string>
- <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"メディアの音声"</string>
+ <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"メディアのオーディオ"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"電話"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ファイル転送"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"入力デバイス"</string>
diff --git a/packages/SettingsLib/res/values-ka/arrays.xml b/packages/SettingsLib/res/values-ka/arrays.xml
index 8d1adf653f97..8ee333835a06 100644
--- a/packages/SettingsLib/res/values-ka/arrays.xml
+++ b/packages/SettingsLib/res/values-ka/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"მხოლოდ მოწყობილობის ეკრანი (ნაგულისხმევი)"</item>
- <item msgid="9161645858025071955">"გარე ეკრანი"</item>
- <item msgid="114384731934682483">"ფოკუსის მიხედვით"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"ჩრდილის ჩვენება მხოლოდ მოწყობილობის ეკრანზე"</item>
- <item msgid="7795034287069726554">"ჩრდილის ჩვენება ერთ გარე ეკრანზე"</item>
- <item msgid="5280431949814340475">"მოწყობილობის ჩვენება ბოლო ფოკუსირებულ ეკრანზე"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml
index e8996de87cb0..6aa5f2b1c4e5 100644
--- a/packages/SettingsLib/res/values-kk/arrays.xml
+++ b/packages/SettingsLib/res/values-kk/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Тек құрылғы дисплейі (әдепкі)"</item>
- <item msgid="9161645858025071955">"Сыртқы дисплей"</item>
- <item msgid="114384731934682483">"Назарға негізделген"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Құрылғы дисплейінде ғана реңк көрсету"</item>
- <item msgid="7795034287069726554">"Жалғыз сыртқы дисплейі бар құрылғыны көрсету"</item>
- <item msgid="5280431949814340475">"Соңғы рет назарда болған дисплейдегі құрылғыны көрсету"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index ebb723ce87c2..9082a5665f92 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -506,7 +506,7 @@
<string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зарядталып жатыр"</string>
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Зарядталып болады: <xliff:g id="TIME">%3$s</xliff:g>"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - Толық заряд алуға қалған уақыт: <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Толық заряд алуға қалған уақыт: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Толықтай зарядталып болады: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"Заряд толуына қалған уақыт: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Жылдам зарядтау"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Әкімші басқарады"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Шектелген параметрлер арқылы басқарылады."</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Қоңырау шалу кезінде қолжетімді емес."</string>
<string name="disabled" msgid="8017887509554714950">"Өшірілген"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Рұқсат берілген"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Рұқсат етілмеген"</string>
diff --git a/packages/SettingsLib/res/values-km/arrays.xml b/packages/SettingsLib/res/values-km/arrays.xml
index ee6ee565fbae..e9a21e87312f 100644
--- a/packages/SettingsLib/res/values-km/arrays.xml
+++ b/packages/SettingsLib/res/values-km/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"ផ្ទាំងអេក្រង់ឧបករណ៍តែប៉ុណ្ណោះ (លំនាំដើម)"</item>
- <item msgid="9161645858025071955">"ផ្ទាំង​អេក្រង់​ខាង​ក្រៅ"</item>
- <item msgid="114384731934682483">"ផ្អែកលើការផ្ដោត"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"បង្ហាញផ្ទាំងនៅលើផ្ទាំងអេក្រង់ឧបករណ៍តែប៉ុណ្ណោះ"</item>
- <item msgid="7795034287069726554">"បង្ហាញឧបករណ៍នៅលើផ្ទាំងអេក្រង់ខាងក្រៅតែមួយ"</item>
- <item msgid="5280431949814340475">"បង្ហាញឧបករណ៍នៅលើផ្ទាំងអេក្រង់ដែលផ្ដោតចុងក្រោយ"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-kn/arrays.xml b/packages/SettingsLib/res/values-kn/arrays.xml
index 51e6e15a3e1b..dc9c7e096ab3 100644
--- a/packages/SettingsLib/res/values-kn/arrays.xml
+++ b/packages/SettingsLib/res/values-kn/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"ಸಾಧನದ ಡಿಸ್‌ಪ್ಲೇ ಮಾತ್ರ (ಡೀಫಾಲ್ಟ್)"</item>
- <item msgid="9161645858025071955">"ಬಾಹ್ಯ ಡಿಸ್‌ಪ್ಲೇ"</item>
- <item msgid="114384731934682483">"ಫೋಕಸ್-ಆಧಾರಿತ"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"ಸಾಧನದ ಡಿಸ್‌ಪ್ಲೇನಲ್ಲಿ ಮಾತ್ರ ಶೇಡ್ ತೋರಿಸಿ"</item>
- <item msgid="7795034287069726554">"ಒಂದೇ ಬಾಹ್ಯ ಡಿಸ್‌ಪ್ಲೇನಲ್ಲಿ ಸಾಧನವನ್ನು ತೋರಿಸಿ"</item>
- <item msgid="5280431949814340475">"ಕೊನೆಯ ಕೇಂದ್ರೀಕೃತ ಡಿಸ್‌ಪ್ಲೇನಲ್ಲಿ ಸಾಧನವನ್ನು ತೋರಿಸಿ"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index b0b6fcac6cf9..d2b217683d41 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"ಫಾಸ್ಟ್ ಚಾರ್ಜಿಂಗ್"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ನಿರ್ವಾಹಕರ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗಿದೆ"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ನಿರ್ಬಂಧಿಸಲಾದ ಸೆಟ್ಟಿಂಗ್ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗುತ್ತದೆ"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ಕರೆಗಳ ಸಮಯದಲ್ಲಿ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="disabled" msgid="8017887509554714950">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"ಅನುಮತಿಸಲಾಗಿದೆ"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"ಅನುಮತಿ ಇಲ್ಲ"</string>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index dd1121f55c04..1477497197c0 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"기기 디스플레이만(기본값)"</item>
- <item msgid="9161645858025071955">"외부 디스플레이"</item>
- <item msgid="114384731934682483">"포커스 기반"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"기기 디스플레이에만 음영 표시"</item>
- <item msgid="7795034287069726554">"단일 외부 디스플레이에 기기 표시"</item>
- <item msgid="5280431949814340475">"마지막으로 포커스된 디스플레이에 기기 표시"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 9a2af376bdc6..bece63792ecb 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"급속 충전"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"관리자가 제어"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"제한된 설정으로 제어됨"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"통화 중에는 사용할 수 없습니다."</string>
<string name="disabled" msgid="8017887509554714950">"사용 안함"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"허용됨"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"허용되지 않음"</string>
diff --git a/packages/SettingsLib/res/values-ky/arrays.xml b/packages/SettingsLib/res/values-ky/arrays.xml
index fe44fe066e46..54d9ecd5fbae 100644
--- a/packages/SettingsLib/res/values-ky/arrays.xml
+++ b/packages/SettingsLib/res/values-ky/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Түзмөктүн экраны гана (демейки)"</item>
- <item msgid="9161645858025071955">"Тышкы экран"</item>
- <item msgid="114384731934682483">"Focus-based"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Көлөкөнү түзмөктүн экранында гана көрсөтүү"</item>
- <item msgid="7795034287069726554">"Түзмөктү бир тышкы экранда көрсөтүү"</item>
- <item msgid="5280431949814340475">"Түзмөктү акыркы активдүү экранда көрсөтүү"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index a756d57b1e96..b6baf38df4d3 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Ыкчам кубаттоо"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Администратор тарабынан көзөмөлдөнөт"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Чектелген параметр аркылуу көзөмөлдөнөт"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Сүйлөшүп жаткан учурда жеткиликсиз"</string>
<string name="disabled" msgid="8017887509554714950">"Өчүрүлгөн"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Уруксат берилген"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Тыюу салынган"</string>
diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml
index d9da45b40f99..ccf645b2d77c 100644
--- a/packages/SettingsLib/res/values-lo/arrays.xml
+++ b/packages/SettingsLib/res/values-lo/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"ຈໍສະແດງຜົນຂອງອຸປະກອນເທົ່ານັ້ນ (ຄ່າເລີ່ມຕົ້ນ)"</item>
- <item msgid="9161645858025071955">"ຈໍສະແດງຜົນພາຍນອກ"</item>
- <item msgid="114384731934682483">"ອີງຕາມການໂຟກັສ"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"ສະແດງເສດສີໃນຈໍສະແດງຜົນຂອງອຸປະກອນເທົ່ານັ້ນ"</item>
- <item msgid="7795034287069726554">"ສະແດງອຸປະກອນໃນຈໍສະແດງຜົນພາຍນອກເຄື່ອງດຽວ"</item>
- <item msgid="5280431949814340475">"ສະແດງອຸປະກອນໃນຈໍສະແດງຜົນທີ່ໂຟກັສຫຼ້າສຸດ"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index 6129af9b5a15..1f40b1a6ed9b 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Tik įrenginio ekranas (numatytasis nustatymas)"</item>
<item msgid="9161645858025071955">"Išorinis ekranas"</item>
- <item msgid="114384731934682483">"Pagal fokusavimą"</item>
+ <item msgid="23651860565814477">"Naujausias būsenos juostos palietimas"</item>
+ <item msgid="7521112827893653392">"Pagal fokusavimą"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Rodyti šešėlį tik įrenginio ekrane"</item>
- <item msgid="7795034287069726554">"Rodyti įrenginį viename išoriniame ekrane"</item>
- <item msgid="5280431949814340475">"Rodyti įrenginį paskutiniame fokusuotame ekrane"</item>
+ <item msgid="1955398604822147783">"Rodyti šešėlį viename išoriniame ekrane"</item>
+ <item msgid="391477482416751568">"Rodyti šešėlį ekrane, kuriame paskutinį kartą buvo sąveikaujama su būsenos juosta"</item>
+ <item msgid="1746820128097981528">"Rodyti šešėlį paskutiniame fokusuotame ekrane"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index caa5b18855a8..f81caa830ddd 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Spartusis įkrovimas"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Valdo administratorius"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Valdoma pagal apribotą nustatymą"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nepasiekiama per skambučius"</string>
<string name="disabled" msgid="8017887509554714950">"Neleidžiama"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Leidžiama"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Neleidžiama"</string>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index 92d141e1723b..6d293be28a4e 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Tikai ierīces displejs (noklusējums)"</item>
- <item msgid="9161645858025071955">"Ārējais displejs"</item>
- <item msgid="114384731934682483">"Saskaņā ar fokusu"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Rādīt ēnu tikai ierīces displejā"</item>
- <item msgid="7795034287069726554">"Rādīt ierīci vienā ārējā displejā"</item>
- <item msgid="5280431949814340475">"Rādīt ierīci pēdējā fokusētajā displejā"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 84bf6929ca03..987857b9a6bd 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Ātrā uzlāde"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolē administrators"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolē ierobežots iestatījums"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ierīce nav pieejama zvanu laikā"</string>
<string name="disabled" msgid="8017887509554714950">"Atspējots"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Atļauts"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Nav atļauts"</string>
diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml
index 8e9bb21ff520..0490f2822c5f 100644
--- a/packages/SettingsLib/res/values-mk/arrays.xml
+++ b/packages/SettingsLib/res/values-mk/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Само на екранот на уредот (стандардно)"</item>
- <item msgid="9161645858025071955">"Надворешен екран"</item>
- <item msgid="114384731934682483">"Засновано на фокус"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Прикажувај сенка само на екранот на уредот"</item>
- <item msgid="7795034287069726554">"Прикажувај сенка на еден надворешен екран"</item>
- <item msgid="5280431949814340475">"Прикажувај сенка на последниот фокусиран екран"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"стандарден_екран"</item>
- <item msgid="774789415968826925">"кој_било_надворешен_екран"</item>
- <item msgid="7880769915418638436">"последен_допир_на_статусната_лента"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index a06da85e0041..fa654379f7ee 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Се полни брзо"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролирано од администраторот"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролирано со ограничени поставки"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Недостапно при повици"</string>
<string name="disabled" msgid="8017887509554714950">"Оневозможено"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Со дозвола"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Без дозвола"</string>
diff --git a/packages/SettingsLib/res/values-ml/arrays.xml b/packages/SettingsLib/res/values-ml/arrays.xml
index 4b8dbce2a523..811c03d5ddcc 100644
--- a/packages/SettingsLib/res/values-ml/arrays.xml
+++ b/packages/SettingsLib/res/values-ml/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"ഉപകരണ ഡിസ്പ്ലേ മാത്രം (ഡിഫോൾട്ട്)"</item>
<item msgid="9161645858025071955">"ബാഹ്യ ഡിസ്പ്ലേ"</item>
- <item msgid="114384731934682483">"ഫോക്കസ്-അടിസ്ഥാനമാക്കിയുള്ളത്"</item>
+ <item msgid="23651860565814477">"ഏറ്റവും പുതിയ സ്റ്റാറ്റസ് ബാർ ടച്ച്"</item>
+ <item msgid="7521112827893653392">"ഫോക്കസ്-അടിസ്ഥാനമാക്കിയുള്ളത്"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"ഉപകരണ ഡിസ്പ്ലേയിൽ മാത്രം ഷെയ്‌ഡ് കാണിക്കുക"</item>
- <item msgid="7795034287069726554">"ഒരൊറ്റ ബാഹ്യ ഡിസ്പ്ലേയിൽ ഉപകരണം കാണിക്കുക"</item>
- <item msgid="5280431949814340475">"അവസാനം ഫോക്കസ് ചെയ്ത ഡിസ്പ്ലേയിൽ ഉപകരണം കാണിക്കുക"</item>
+ <item msgid="1955398604822147783">"ഒരൊറ്റ ബാഹ്യ ഡിസ്പ്ലേയിൽ ഷെയ്‌ഡ് കാണിക്കുക"</item>
+ <item msgid="391477482416751568">"അവസാനം അതിന്റെ സ്റ്റാറ്റസ് ബാർ ഇടപഴകിയ ഡിസ്പ്ലേയിൽ ഷെയ്‌ഡ് കാണിക്കുക"</item>
+ <item msgid="1746820128097981528">"അവസാനം ഫോക്കസ് ചെയ്ത ഡിസ്പ്ലേയിൽ ഷേഡ് കാണിക്കുക"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-mn/arrays.xml b/packages/SettingsLib/res/values-mn/arrays.xml
index 5d5b8f9af59c..ca103afc9bbc 100644
--- a/packages/SettingsLib/res/values-mn/arrays.xml
+++ b/packages/SettingsLib/res/values-mn/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Зөвхөн төхөөрөмжийн дэлгэц (өгөгдмөл)"</item>
- <item msgid="9161645858025071955">"Гаднын дэлгэц"</item>
- <item msgid="114384731934682483">"Төвлөрөлд тулгуурласан"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Зөвхөн төхөөрөмж дээрх дэлгэцэд сүүдрийг харуулах"</item>
- <item msgid="7795034287069726554">"Зөвхөн гаднын нэг дэлгэц дээр төхөөрөмжийг харуулах"</item>
- <item msgid="5280431949814340475">"Сүүлд төвлөрсөн дэлгэц дээр төхөөрөмжийг харуулах"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index c165213214da..e8e9e0caf08a 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Шуурхай цэнэглэх"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Админ удирдсан"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Хязгаарлагдсан тохиргоогоор хянадаг"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Дуудлагын үер боломжгүй"</string>
<string name="disabled" msgid="8017887509554714950">"Идэвхгүйжүүлсэн"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Зөвшөөрсөн"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Зөвшөөрөөгүй"</string>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index 959499c931f3..1437a2cd8660 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"फक्त डिव्हाइस डिस्प्ले (डीफॉल्ट)"</item>
- <item msgid="9161645858025071955">"बाह्य डिस्प्ले"</item>
- <item msgid="114384731934682483">"फोकसवर आधारित"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"फक्त डिव्हाइस डिस्प्लेवर शेड दाखवा"</item>
- <item msgid="7795034287069726554">"एकल बाह्य डिस्प्लेवर डिव्हाइस दाखवा"</item>
- <item msgid="5280431949814340475">"शेवटच्या फोकस केलेल्या डिस्प्लेवर डिव्हाइस दाखवा"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index d47f8ffd3c99..f1f5cab8d6a7 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"फास्ट चार्जिंग"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"प्रशासकाने नियंत्रित केलेले"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"प्रतिबंधित केलेल्या सेटिंग द्वारे नियंत्रित"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"कॉल दरम्‍यान उपलब्ध नाही"</string>
<string name="disabled" msgid="8017887509554714950">"अक्षम"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"अनुमती आहे"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"अनुमती नाही"</string>
diff --git a/packages/SettingsLib/res/values-ms/arrays.xml b/packages/SettingsLib/res/values-ms/arrays.xml
index 7b6cbe17b5d0..464a0c73c734 100644
--- a/packages/SettingsLib/res/values-ms/arrays.xml
+++ b/packages/SettingsLib/res/values-ms/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Paparan peranti sahaja (Lalai)"</item>
<item msgid="9161645858025071955">"Paparan luaran"</item>
- <item msgid="114384731934682483">"Berasaskan fokus"</item>
+ <item msgid="23651860565814477">"Sentuhan bar status terbaharu"</item>
+ <item msgid="7521112827893653392">"Berasaskan fokus"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Tunjukkan rona warna pada paparan peranti sahaja"</item>
- <item msgid="7795034287069726554">"Tunjukkan peranti pada satu paparan luaran"</item>
- <item msgid="5280431949814340475">"Tunjukkan peranti pada paparan terakhir yang difokuskan"</item>
+ <item msgid="1955398604822147783">"Tunjukkan rona warna pada satu paparan luaran"</item>
+ <item msgid="391477482416751568">"Tunjukkan rona warna pada paparan yang terakhir berinteraksi dengan bar status"</item>
+ <item msgid="1746820128097981528">"Tunjukkan rona warna pada paparan fokus terakhir"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml
index 71a1c7c5649b..aef22b2203de 100644
--- a/packages/SettingsLib/res/values-my/arrays.xml
+++ b/packages/SettingsLib/res/values-my/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"စက်ဖန်သားပြင် သီးသန့် (မူရင်း)"</item>
- <item msgid="9161645858025071955">"ပြင်ပဖန်သားပြင်"</item>
- <item msgid="114384731934682483">"ပြသမှုအခြေပြု"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"စက်ဖန်သားပြင်တွင်သာ အရိပ်ပြပါ"</item>
- <item msgid="7795034287069726554">"ပြင်ပဖန်သားပြင်တစ်ခုတွင် စက်ကိုပြပါ"</item>
- <item msgid="5280431949814340475">"နောက်ဆုံးပြသထားသော ဖန်သားပြင်တွင် စက်ကိုပြပါ"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"မူရင်းဖန်သားပြင်"</item>
- <item msgid="774789415968826925">"မည်သည့်ပြင်ပဖန်သားပြင်မဆို"</item>
- <item msgid="7880769915418638436">"အခြေအနေပြဘား နောက်ဆုံးထိတွေ့မှု"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 4ba82fdd8a1d..cf493cf40a9c 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"အမြန်အားသွင်းခြင်း"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"စီမံခန့်ခွဲသူမှ ထိန်းချုပ်ပါသည်"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ကန့်သတ်ဆက်တင်ဖြင့် ထိန်းချုပ်ထားသည်"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ဖုန်းခေါ်ဆိုနေချိန်တွင် မရနိုင်ပါ"</string>
<string name="disabled" msgid="8017887509554714950">"ပိတ်ထားပြီး"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"ခွင့်ပြုထားသည်"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"ခွင့်မပြုပါ"</string>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index 8d52693a5f16..88f193c119fc 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Bare enhetsskjermen (standard)"</item>
- <item msgid="9161645858025071955">"Ekstern skjerm"</item>
- <item msgid="114384731934682483">"Fokusbasert"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Vis skyggen bare på enhetsskjermen"</item>
- <item msgid="7795034287069726554">"Vis enheten på én ekstern skjerm"</item>
- <item msgid="5280431949814340475">"Vis enheten på den sist fokuserte skjermen"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"Standardskjerm"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index f6de3466a816..045318a765b7 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Hurtiglading"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrollert av administratoren"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrollert av en begrenset innstilling"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Utilgjengelig under samtaler"</string>
<string name="disabled" msgid="8017887509554714950">"Deaktivert"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Tillatt"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Ikke tillatt"</string>
diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml
index cd8448f684dd..1989994a289c 100644
--- a/packages/SettingsLib/res/values-ne/arrays.xml
+++ b/packages/SettingsLib/res/values-ne/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"२"</item>
<item msgid="4779928470672877922">"३"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"डिभाइसको डिस्प्ले मात्र (डिफल्ट)"</item>
- <item msgid="9161645858025071955">"बाह्य डिस्प्ले"</item>
- <item msgid="114384731934682483">"फोकसमा आधारित"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"यो सेड डिभाइसकै डिस्प्लेमा मात्र देखाउनुहोस्"</item>
- <item msgid="7795034287069726554">"यो डिभाइस एकल बाह्य डिस्प्लेमा देखाउनुहोस्"</item>
- <item msgid="5280431949814340475">"यो डिभाइस पछिल्लो पटक फोकस गरिएको डिस्प्लेमा देखाउनुहोस्"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 28d02a14c484..d637a4bb9640 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -262,7 +262,7 @@
<string name="adb_paired_devices_title" msgid="5268997341526217362">"कनेक्ट गरिएका डिभाइस"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"हाल जोडिएको छ"</string>
<string name="adb_wireless_device_details_title" msgid="7129369670526565786">"डिभाइसको विवरण"</string>
- <string name="adb_device_forget" msgid="193072400783068417">"बिर्सनुहोस्"</string>
+ <string name="adb_device_forget" msgid="193072400783068417">"हटाउनुहोस्"</string>
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"डिभाइसको फिंगरप्रिन्ट: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"वायरलेसमा जोड्न सकिएन"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> सही नेटवर्कमा जोडिएको कुरा सुनिश्चित गर्नुहोस्"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"फास्ट चार्जिङ"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"प्रशासकद्वारा नियन्त्रित"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"प्रतिबन्धित सेटिङले नियन्त्रण गरेको"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"कल चलिरहेका बेला उपलब्ध छैन"</string>
<string name="disabled" msgid="8017887509554714950">"असक्षम पारियो"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"अनुमति छ"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"अनुमति छैन"</string>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index d92b806acf49..12c9551d850f 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Alleen apparaatscherm (standaard)"</item>
- <item msgid="9161645858025071955">"Extern scherm"</item>
- <item msgid="114384731934682483">"Op focus gebaseerd"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Alleen paneel tonen op apparaatscherm"</item>
- <item msgid="7795034287069726554">"Apparaat tonen op één extern scherm"</item>
- <item msgid="5280431949814340475">"Apparaat tonen op laatste gefocuste scherm"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml
index f9beb8afd4d0..97823036d96a 100644
--- a/packages/SettingsLib/res/values-or/arrays.xml
+++ b/packages/SettingsLib/res/values-or/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"କେବଳ ଡିଭାଇସ ଡିସପ୍ଲେ (ଡିଫଲ୍ଟ)"</item>
- <item msgid="9161645858025071955">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେ"</item>
- <item msgid="114384731934682483">"ଫୋକସ-ଆଧାରିତ"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"କେବଳ ଡିଭାଇସରେ ଡିସପ୍ଲେ ସେଡ ଦେଖାନ୍ତୁ"</item>
- <item msgid="7795034287069726554">"ସିଙ୍ଗଲ ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେରେ ଡିଭାଇସ ଦେଖାନ୍ତୁ"</item>
- <item msgid="5280431949814340475">"ଫୋକସ କରାଯାଇଥିବା ଗତ ଡିସପ୍ଲେରେ ଡିଭାଇସ ଦେଖାନ୍ତୁ"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 69d57a6803d0..bcde4e9bb831 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -129,7 +129,7 @@
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"ଇନପୁଟ ଡିଭାଇସ"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"ଇଣ୍ଟରନେଟ ଆକ୍ସେସ"</string>
<string name="bluetooth_profile_pbap" msgid="2103406516858653017">"କଣ୍ଟାକ୍ଟ ଓ କଲ ଇତିହାସକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
- <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"ସୂଚନାକୁ କଲ ଘୋଷଣା ଏବଂ ଆହୁରି ଅଧିକ ପାଇଁ ବ୍ୟବହାର କରାଯିବ"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"ସୂଚନାକୁ କଲ ଘୋଷଣା ଏବଂ ଆହୁରି ଅନେକ କିଛି ପାଇଁ ବ୍ୟବହାର କରାଯିବ"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ଇଣ୍ଟର୍‌ନେଟ୍‌ ସଂଯୋଗ ଶେୟାରିଙ୍ଗ"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"ଟେକ୍ସଟ୍ ମେସେଜ୍"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM ଆକ୍ସେସ"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"ଫାଷ୍ଟ ଚାର୍ଜିଂ"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ଆଡ୍‌ମିନ୍‌ ଦ୍ୱାରା ନିୟନ୍ତ୍ରିତ"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ପ୍ରତିବନ୍ଧିତ ସେଟିଂ ଦ୍ୱାରା ନିୟନ୍ତ୍ରଣ କରାଯାଇଛି"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"କଲ କରିବାବେଳେ ଉପଲବ୍ଧ ନଥାଏ"</string>
<string name="disabled" msgid="8017887509554714950">"ଅକ୍ଷମ ହୋଇଛି"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"ଅନୁମତି ଦିଆଯାଇଛି"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"ଅନୁମତି ନାହିଁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml
index 1e7f05512d33..afb85cae2d1e 100644
--- a/packages/SettingsLib/res/values-pa/arrays.xml
+++ b/packages/SettingsLib/res/values-pa/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"ਸਿਰਫ਼ ਡੀਵਾਈਸ ਦੀ ਡਿਸਪਲੇ (ਪੂਰਵ-ਨਿਰਧਾਰਿਤ)"</item>
- <item msgid="9161645858025071955">"ਬਾਹਰੀ ਡਿਸਪਲੇ"</item>
- <item msgid="114384731934682483">"ਫੋਕਸ-ਆਧਾਰਿਤ"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"ਸਿਰਫ਼ ਡੀਵਾਈਸ ਦੀ ਡਿਸਪਲੇ \'ਤੇ ਸ਼ੇਡ ਦਿਖਾਓ"</item>
- <item msgid="7795034287069726554">"ਇਕਹਿਰੀ ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਡੀਵਾਈਸ ਦਿਖਾਓ"</item>
- <item msgid="5280431949814340475">"ਫੋਕਸ ਕੀਤੀ ਗਈ ਪਿਛਲੀ ਡਿਸਪਲੇ \'ਤੇ ਡੀਵਾਈਸ ਦਿਖਾਓ"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index e12c2c01e6ae..821c84e20901 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -128,7 +128,7 @@
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"ਇਨਪੁੱਟ ਡੀਵਾਈਸ"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ"</string>
- <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"ਸੰਪਰਕਾਂ ਅਤੇ ਕਾਲ ਇਤਿਹਾਸ \'ਤੇ ਪਹੁੰਚ ਕਰਨ ਦਿਓ"</string>
+ <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"ਸੰਪਰਕਾਂ ਅਤੇ ਕਾਲ ਇਤਿਹਾਸ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦਿਓ"</string>
<string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"ਜਾਣਕਾਰੀ ਦੀ ਵਰਤੋਂ ਕਾਲ ਘੋਸ਼ਣਾਵਾਂ ਅਤੇ ਹੋਰ ਚੀਜ਼ਾਂ ਲਈ ਕੀਤੀ ਜਾਵੇਗੀ"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਸਾਂਝਾਕਰਨ"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"ਲਿਖਤ ਸੁਨੇਹੇ"</string>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index a9892b3688c8..59791c0e70b6 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Tylko wyświetlanie na urządzeniu (domyślnie)"</item>
- <item msgid="9161645858025071955">"Wyświetlacz zewnętrzny"</item>
- <item msgid="114384731934682483">"Na podstawie zaznaczenia"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Pokaż cień tylko na wyświetlaczu urządzenia"</item>
- <item msgid="7795034287069726554">"Pokaż urządzenie na pojedynczym wyświetlaczu zewnętrznym"</item>
- <item msgid="5280431949814340475">"Pokaż urządzenie na ostatnim aktywnym wyświetlaczu"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 9fc2765ba59c..9f6eb4c6a7c7 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Szybkie ładowanie"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolowane przez administratora"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Obowiązują ustawienia z ograniczonym dostępem"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Niedostępne w trakcie połączeń"</string>
<string name="disabled" msgid="8017887509554714950">"Wyłączona"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Dozwolone"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Niedozwolone"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index 35aa3b0834c3..2e61272269a0 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Somente a tela do dispositivo (padrão)"</item>
<item msgid="9161645858025071955">"Tela externa"</item>
- <item msgid="114384731934682483">"Com base no foco"</item>
+ <item msgid="23651860565814477">"Toque mais recente na barra de status"</item>
+ <item msgid="7521112827893653392">"Com base no foco"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Mostrar sombra apenas na tela do dispositivo"</item>
- <item msgid="7795034287069726554">"Mostrar o dispositivo em uma única tela externa"</item>
- <item msgid="5280431949814340475">"Mostrar o dispositivo na última tela focada"</item>
+ <item msgid="1955398604822147783">"Mostrar sombra em uma única tela externa"</item>
+ <item msgid="391477482416751568">"Mostrar sombra na tela que teve a última interação na barra de status"</item>
+ <item msgid="1746820128097981528">"Mostrar sombra na última tela focada"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 1e45965df421..72f25be8e66f 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -123,13 +123,13 @@
<string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas mídia), apenas esquerdo"</string>
<string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ativo (apenas mídia), somente direito"</string>
<string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ativo (apenas mídia), esquerdo e direito"</string>
- <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Áudio da mídia"</string>
+ <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Áudio de mídia"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Chamadas telefônicas"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferência de arquivo"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Dispositivo de entrada"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"Acesso à Internet"</string>
<string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Permitir acesso a contatos e ao histórico de ligações"</string>
- <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"As informações serão usadas para fazer o anúncio de ligações e mais"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"As informações serão usadas para avisar sobre ligações e mais"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Compartilhamento de conexão à Internet"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"Mensagens de texto"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acesso ao chip"</string>
@@ -515,7 +515,7 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregando sem fio"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Carregando"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está carregando"</string>
- <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectado, mas não está carregando"</string>
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Dispositivo conectado, mas não está carregando"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Carga completa"</string>
<string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Carregamento suspenso"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Carregamento rápido"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlada pelo admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlada pelas configurações restritas"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponível durante ligações"</string>
<string name="disabled" msgid="8017887509554714950">"Desativado"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Permitido"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Não permitido"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index 2829f20722f7..64fad64ff9c4 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Apenas no ecrã do dispositivo (predefinição)"</item>
<item msgid="9161645858025071955">"Ecrã externo"</item>
- <item msgid="114384731934682483">"Com base no foco"</item>
+ <item msgid="23651860565814477">"Toque mais recente na barra de estado"</item>
+ <item msgid="7521112827893653392">"Com base no foco"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Mostrar a sombra apenas no ecrã do dispositivo"</item>
- <item msgid="7795034287069726554">"Mostrar o dispositivo num único ecrã externo"</item>
- <item msgid="5280431949814340475">"Apresente o dispositivo no último ecrã focado"</item>
+ <item msgid="1955398604822147783">"Mostrar a sombra num único ecrã externo"</item>
+ <item msgid="391477482416751568">"Mostrar a sombra no ecrã em que ocorreu a última interação com a barra de estado"</item>
+ <item msgid="1746820128097981528">"Mostrar a sombra no último ecrã focado"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index 35aa3b0834c3..2e61272269a0 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Somente a tela do dispositivo (padrão)"</item>
<item msgid="9161645858025071955">"Tela externa"</item>
- <item msgid="114384731934682483">"Com base no foco"</item>
+ <item msgid="23651860565814477">"Toque mais recente na barra de status"</item>
+ <item msgid="7521112827893653392">"Com base no foco"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Mostrar sombra apenas na tela do dispositivo"</item>
- <item msgid="7795034287069726554">"Mostrar o dispositivo em uma única tela externa"</item>
- <item msgid="5280431949814340475">"Mostrar o dispositivo na última tela focada"</item>
+ <item msgid="1955398604822147783">"Mostrar sombra em uma única tela externa"</item>
+ <item msgid="391477482416751568">"Mostrar sombra na tela que teve a última interação na barra de status"</item>
+ <item msgid="1746820128097981528">"Mostrar sombra na última tela focada"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 1e45965df421..72f25be8e66f 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -123,13 +123,13 @@
<string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas mídia), apenas esquerdo"</string>
<string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ativo (apenas mídia), somente direito"</string>
<string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ativo (apenas mídia), esquerdo e direito"</string>
- <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Áudio da mídia"</string>
+ <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Áudio de mídia"</string>
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"Chamadas telefônicas"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferência de arquivo"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Dispositivo de entrada"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"Acesso à Internet"</string>
<string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Permitir acesso a contatos e ao histórico de ligações"</string>
- <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"As informações serão usadas para fazer o anúncio de ligações e mais"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"As informações serão usadas para avisar sobre ligações e mais"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Compartilhamento de conexão à Internet"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"Mensagens de texto"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acesso ao chip"</string>
@@ -515,7 +515,7 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregando sem fio"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Carregando"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está carregando"</string>
- <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectado, mas não está carregando"</string>
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Dispositivo conectado, mas não está carregando"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Carga completa"</string>
<string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Carregamento suspenso"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Carregamento rápido"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlada pelo admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlada pelas configurações restritas"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponível durante ligações"</string>
<string name="disabled" msgid="8017887509554714950">"Desativado"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Permitido"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Não permitido"</string>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index dba734c588aa..8bfeb70d0fe4 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Numai pe ecranul dispozitivului (prestabilit)"</item>
- <item msgid="9161645858025071955">"Ecran extern"</item>
- <item msgid="114384731934682483">"În funcție de focalizare"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Afișează umbra doar pe ecranul dispozitivului"</item>
- <item msgid="7795034287069726554">"Afișează dispozitivul pe un singur ecran extern"</item>
- <item msgid="5280431949814340475">"Afișează dispozitivul pe ultimul ecran focalizat"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index af09734842c1..26fdce813a04 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Încărcare rapidă"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlată de administrator"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlată de setarea restricționată"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Indisponibil în timpul apelurilor"</string>
<string name="disabled" msgid="8017887509554714950">"Dezactivată"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Permise"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Nepermise"</string>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index f0782eb04b7e..52b2549dd60e 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Только экран устройства (по умолчанию)"</item>
- <item msgid="9161645858025071955">"Внешний дисплей"</item>
- <item msgid="114384731934682483">"Активный дисплей"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Показывать тень только на экране устройства"</item>
- <item msgid="7795034287069726554">"Показывать устройство на одном внешнем дисплее"</item>
- <item msgid="5280431949814340475">"Показывать устройство на последнем активном дисплее"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-si/arrays.xml b/packages/SettingsLib/res/values-si/arrays.xml
index 855bbc9842a8..66f1ba757a68 100644
--- a/packages/SettingsLib/res/values-si/arrays.xml
+++ b/packages/SettingsLib/res/values-si/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"උපාංග සංදර්ශකය පමණි (පෙරනිමි)"</item>
- <item msgid="9161645858025071955">"බාහිර සංදර්ශකය"</item>
- <item msgid="114384731934682483">"නාභිගත කිරීම-පාදක"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"උපාංග සංදර්ශකයේ පමණක් සෙවන පෙන්වන්න"</item>
- <item msgid="7795034287069726554">"උපාංගය තනි බාහිර සංදර්ශකයක පෙන්වන්න"</item>
- <item msgid="5280431949814340475">"අවසන් වරට නාභිගත කළ සංදර්ශකයේ උපාංගය පෙන්වන්න"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 1b02d28e8685..94e1ed429de6 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"වේගවත් ආරෝපණය"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"පරිපාලක විසින් පාලනය කරන ලදී"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"සීමා කළ සැකසීම මගින් පාලනය වේ"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"ඇමතුම් අතරතුර නොපවතී"</string>
<string name="disabled" msgid="8017887509554714950">"අබල කර ඇත"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"ඉඩ දුන්"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"ඉඩ නොදෙන"</string>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index 3473e282e59c..f8363cdfc447 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Iba obrazovka zariadenia (predvolené)"</item>
- <item msgid="9161645858025071955">"Externá obrazovka"</item>
- <item msgid="114384731934682483">"Na základe označenia"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Zobraziť panel iba na obrazovke zariadenia"</item>
- <item msgid="7795034287069726554">"Zobraziť zariadenie na jednej externej obrazovke"</item>
- <item msgid="5280431949814340475">"Zobraziť zariadenie na poslednej označenej obrazovke"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index c3bf79c34ea6..2a128efde3bc 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Prikaz samo v napravi (privzeto)"</item>
- <item msgid="9161645858025071955">"Zunanji zaslon"</item>
- <item msgid="114384731934682483">"Na podlagi fokusa"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Prikaz podokna samo na zaslonu naprave"</item>
- <item msgid="7795034287069726554">"Prikaz naprave na enem zunanjem zaslonu"</item>
- <item msgid="5280431949814340475">"Prikaz naprave na zadnjem zaslonu s fokusom"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-sq/arrays.xml b/packages/SettingsLib/res/values-sq/arrays.xml
index 7136bf75eaee..3b0994a7d93f 100644
--- a/packages/SettingsLib/res/values-sq/arrays.xml
+++ b/packages/SettingsLib/res/values-sq/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Vetëm ekrani i pajisjes (parazgjedhja)"</item>
- <item msgid="9161645858025071955">"Ekrani i jashtëm"</item>
- <item msgid="114384731934682483">"Bazuar te fokusi"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Shfaq hijen vetëm në ekranin e pajisjes"</item>
- <item msgid="7795034287069726554">"Shfaq pajisjen në një ekran të vetëm të jashtëm"</item>
- <item msgid="5280431949814340475">"Shfaq pajisjen në ekranin e fundit të fokusuar"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index e98046ea9a8b..2d2c02b31df3 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Karikim i shpejtë"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolluar nga administratori"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrollohet nga \"Cilësimet e kufizuara\""</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Nuk ofrohet gjatë telefonatave"</string>
<string name="disabled" msgid="8017887509554714950">"Çaktivizuar"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Lejohet"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Nuk lejohet"</string>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index 84d0a7e055c1..fd23a64b98f6 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Приказ само на уређају (подразумевано)"</item>
<item msgid="9161645858025071955">"Спољни екран"</item>
- <item msgid="114384731934682483">"Засновано на фокусу"</item>
+ <item msgid="23651860565814477">"Додир на најновијој статусној траци"</item>
+ <item msgid="7521112827893653392">"Засновано на фокусу"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Прикажи сенку само на екрану уређаја"</item>
- <item msgid="7795034287069726554">"Прикажи уређај на једном спољном екрану"</item>
- <item msgid="5280431949814340475">"Прикажи уређај на последњем екрану у фокусу"</item>
+ <item msgid="1955398604822147783">"Прикажи сенку на једном спољном екрану"</item>
+ <item msgid="391477482416751568">"Прикажи сенку на екрану са којим је статусна трака последњи пут била у интеракцији"</item>
+ <item msgid="1746820128097981528">"Прикажи сенку на последњем екрану у фокусу"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index b5ae7ddf7a31..8a77fdd11742 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Endast enhetens skärm (standard)"</item>
<item msgid="9161645858025071955">"Extern skärm"</item>
- <item msgid="114384731934682483">"Fokusbaserad"</item>
+ <item msgid="23651860565814477">"Senaste interaktion med statusfältet"</item>
+ <item msgid="7521112827893653392">"Fokusbaserad"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Visa endast skugga på enhetens skärm"</item>
- <item msgid="7795034287069726554">"Visa skugga på en enda extern skärm"</item>
- <item msgid="5280431949814340475">"Visa enheten på skärmen som sist var i fokus"</item>
+ <item msgid="1955398604822147783">"Visa skugga på en enda extern skärm"</item>
+ <item msgid="391477482416751568">"Visa skugga på skärmen där statusfältet senast interagerades med"</item>
+ <item msgid="1746820128097981528">"Visa skugga på skärmen som sist var i fokus"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 4f8ea1e03219..e0897cb87e54 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Snabbladdning"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Strys av administratören"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Styrs av spärrad inställning"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Ej tillgänglig under samtal"</string>
<string name="disabled" msgid="8017887509554714950">"Inaktiverad"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Tillåts"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Tillåts inte"</string>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index 145b56c354cf..652c3588d694 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Kwenye skrini ya kifaa pekee (Chaguomsingi)"</item>
- <item msgid="9161645858025071955">"Skrini ya nje"</item>
- <item msgid="114384731934682483">"Inayoangaziwa"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Onyesha kiwango kwenye skrini ya kifaa pekee"</item>
- <item msgid="7795034287069726554">"Onyesha kifaa kwenye skrini moja ya nje"</item>
- <item msgid="5280431949814340475">"Onyesha kifaa kwenye skrini ya mwisho iliyoangaziwa"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 2b175f5939a6..f12597f640a5 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Inachaji kwa kasi"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Imedhibitiwa na msimamizi"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Imedhibitiwa na Mpangilio wenye Mipaka"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Haipatikani wakati unaongea kwa simu"</string>
<string name="disabled" msgid="8017887509554714950">"Imezimwa"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Imeruhusiwa"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Hairuhusiwi"</string>
diff --git a/packages/SettingsLib/res/values-ta/arrays.xml b/packages/SettingsLib/res/values-ta/arrays.xml
index 68812894386b..503cd8f97046 100644
--- a/packages/SettingsLib/res/values-ta/arrays.xml
+++ b/packages/SettingsLib/res/values-ta/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"சாதனக் காட்சி மட்டும் (இயல்பு)"</item>
- <item msgid="9161645858025071955">"வெளிப்புறக் காட்சி"</item>
- <item msgid="114384731934682483">"ஃபோகஸ் அடிப்படையிலானது"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"சாதனக் காட்சியில் மட்டும் ஷேடைக் காட்டும்"</item>
- <item msgid="7795034287069726554">"ஒற்றை வெளிப்புறக் காட்சியில் சாதனத்தைக் காட்டும்"</item>
- <item msgid="5280431949814340475">"கடைசியாக ஃபோகஸ் செய்யப்பட்ட காட்சியில் சாதனத்தைக் காட்டும்"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index dd5a5a4b7d8f..1bd2c3419860 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"விரைவு சார்ஜிங்"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"நிர்வாகி கட்டுப்படுத்துகிறார்"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"வரையறுக்கப்பட்ட அமைப்பால் கட்டுப்படுத்தப்படுகிறது"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"அழைப்புகளின்போது பயன்படுத்த முடியாது"</string>
<string name="disabled" msgid="8017887509554714950">"முடக்கப்பட்டது"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"அனுமதிக்கப்பட்டது"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"அனுமதிக்கப்படவில்லை"</string>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index 8dea6ed2d013..f72e4cd9f9fe 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"పరికర డిస్‌ప్లేలో మాత్రమే (ఆటోమేటిక్ సెట్టింగ్)"</item>
- <item msgid="9161645858025071955">"ఎక్స్‌టర్నల్ డిస్‌ప్లే"</item>
- <item msgid="114384731934682483">"ఫోకస్-ఆధారిత"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"షేడ్‌ను పరికర డిస్‌ప్లేలో మాత్రమే చూపండి"</item>
- <item msgid="7795034287069726554">"పరికరాన్ని ఒక ఎక్స్‌టర్నల్ డిస్‌ప్లేలో మాత్రమే చూపండి"</item>
- <item msgid="5280431949814340475">"పరికరాన్ని చివరగా యాక్టివ్‌గా ఉన్న స్క్రీన్‌లో చూపండి"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 12e45c2b824d..010344f2e103 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"ఫాస్ట్ ఛార్జింగ్"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"నిర్వాహకుని ద్వారా నియంత్రించబడింది"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"పరిమితం చేసిన సెట్టింగ్ ద్వారా నియంత్రించబడుతుంది"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"కాల్స్ సమయంలో అందుబాటులో ఉండదు"</string>
<string name="disabled" msgid="8017887509554714950">"డిజేబుల్ చేయబడింది"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"అనుమతించినవి"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"అనుమతించబడలేదు"</string>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 11cb2ec4e161..adb274d26f9c 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"จอแสดงผลของอุปกรณ์เท่านั้น (ค่าเริ่มต้น)"</item>
- <item msgid="9161645858025071955">"จอแสดงผลภายนอก"</item>
- <item msgid="114384731934682483">"Focus-based"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"แสดงเฉดสีในจอแสดงผลของอุปกรณ์เท่านั้น"</item>
- <item msgid="7795034287069726554">"แสดงอุปกรณ์ในจอแสดงผลภายนอกเครื่องเดียว"</item>
- <item msgid="5280431949814340475">"แสดงอุปกรณ์ในจอแสดงผลที่โฟกัสล่าสุด"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index eae269cc4972..0153375a5c2c 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Display ng device lang (Default)"</item>
- <item msgid="9161645858025071955">"External na display"</item>
- <item msgid="114384731934682483">"Focus-based"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Ipakita ang shade sa display ng device lang"</item>
- <item msgid="7795034287069726554">"Ipakita ang device sa isang external na display"</item>
- <item msgid="5280431949814340475">"Ipakita ang device sa huling na-focus na display"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index fdb9d217e611..6fbbb129b56b 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Yalnızca cihaz ekranı (Varsayılan)"</item>
- <item msgid="9161645858025071955">"Harici ekran"</item>
- <item msgid="114384731934682483">"Odaklanmaya dayalı"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Gölgeyi yalnızca cihaz ekranında göster"</item>
- <item msgid="7795034287069726554">"Cihazı tek bir harici ekranda göster"</item>
- <item msgid="5280431949814340475">"Cihazı son odaklanılan ekranda göster"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 8dcc48f556fd..c99322324a66 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Hızlı şarj"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Yönetici tarafından denetleniyor"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kısıtlanmış ayar tarafından kontrol ediliyor"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Telefon aramaları sırasında kullanılamaz"</string>
<string name="disabled" msgid="8017887509554714950">"Devre dışı"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"İzin verildi"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"İzin verilmiyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index 29494716bbb9..a371c9c5d0f5 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Лише екран пристрою (за умовчанням)"</item>
- <item msgid="9161645858025071955">"Зовнішній дисплей"</item>
- <item msgid="114384731934682483">"На основі фокусування"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Показувати панель лише на екрані пристрою"</item>
- <item msgid="7795034287069726554">"Показувати панель на одному зовнішньому дисплеї"</item>
- <item msgid="5280431949814340475">"Показувати панель на останньому активному дисплеї"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 259cf6c3a0f0..fd1ade641d95 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Швидке заряджання"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Керується адміністратором"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Керується налаштуваннями з обмеженнями"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Недоступно під час викликів"</string>
<string name="disabled" msgid="8017887509554714950">"Вимкнено"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Дозволено"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Заборонено"</string>
diff --git a/packages/SettingsLib/res/values-ur/arrays.xml b/packages/SettingsLib/res/values-ur/arrays.xml
index a9eadb83bbfa..5ce9fb41dcb7 100644
--- a/packages/SettingsLib/res/values-ur/arrays.xml
+++ b/packages/SettingsLib/res/values-ur/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"صرف آلے کا ڈسپلے (ڈیفالٹ)"</item>
<item msgid="9161645858025071955">"بیرونی ڈسپلے"</item>
- <item msgid="114384731934682483">"فوکس پر مبنی"</item>
+ <item msgid="23651860565814477">"تازہ ترین اسٹیٹس بار ٹچ"</item>
+ <item msgid="7521112827893653392">"فوکس پر مبنی"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"صرف آلے کے ڈسپلے پر شیڈ دکھائیں"</item>
- <item msgid="7795034287069726554">"آلے کو واحد بیرونی ڈسپلے پر دکھائیں"</item>
- <item msgid="5280431949814340475">"آلے کو آخری فوکس کردہ ڈسپلے پر دکھائیں"</item>
+ <item msgid="1955398604822147783">"واحد بیرونی ڈسپلے پر شیڈ دکھائیں"</item>
+ <item msgid="391477482416751568">"اس ڈسپلے پر شیڈ دکھائیں جس کے اسٹیٹس بار کے ساتھ آخری بار تعامل کیا گیا تھا"</item>
+ <item msgid="1746820128097981528">"شیڈ کو آخری فوکس کردہ ڈسپلے پر دکھائیں"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 425a0ede22a3..13ffeb125972 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"فاسٹ چارجنگ"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"کنٹرول کردہ بذریعہ منتظم"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"محدود کردہ ترتیب کے زیر انتظام ہے"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"کالز کے دوران غیر دستیاب"</string>
<string name="disabled" msgid="8017887509554714950">"غیر فعال"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"اجازت ہے"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"اجازت نہیں ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml
index f3cae4192180..cf1a0965935f 100644
--- a/packages/SettingsLib/res/values-uz/arrays.xml
+++ b/packages/SettingsLib/res/values-uz/arrays.xml
@@ -291,16 +291,19 @@
<string-array name="shade_display_awareness_entries">
<item msgid="816770658383209617">"Faqat qurilma displeyi (birlamchi)"</item>
<item msgid="9161645858025071955">"Tashqi displey"</item>
- <item msgid="114384731934682483">"Fokusga asoslangan"</item>
+ <item msgid="23651860565814477">"Holat qatori bilan oxirgi oʻzaro aloqa"</item>
+ <item msgid="7521112827893653392">"Fokusga asoslangan"</item>
</string-array>
<string-array name="shade_display_awareness_summaries">
<item msgid="2964753205732912921">"Faqat qurilma displeyida soyani koʻrsatish"</item>
- <item msgid="7795034287069726554">"Qurilmani alohida tashqi displeyda koʻrsatish"</item>
- <item msgid="5280431949814340475">"Qurilmani oxirgi fokuslangan displeyda koʻrsatish"</item>
+ <item msgid="1955398604822147783">"Soyani alohida tashqi displeyda koʻrsatish"</item>
+ <item msgid="391477482416751568">"Oxirgi marta holat qatori qaysi soya bilan munosabatga kirishganini koʻrsatish"</item>
+ <item msgid="1746820128097981528">"Soyani oxirgi fokuslangan displeyda koʻrsatish"</item>
</string-array>
<string-array name="shade_display_awareness_values">
<item msgid="3055776101992426514">"default_display"</item>
<item msgid="774789415968826925">"any_external_display"</item>
<item msgid="7880769915418638436">"status_bar_latest_touch"</item>
+ <item msgid="4313165186636015195">"focused_display"</item>
</string-array>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index e0ebc9faab9c..8e4cf53cfc39 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Chỉ hiển thị trên thiết bị (Mặc định)"</item>
- <item msgid="9161645858025071955">"Màn hình ngoài"</item>
- <item msgid="114384731934682483">"Theo tiêu điểm"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Chỉ hiện ngăn thông báo trên màn hình thiết bị"</item>
- <item msgid="7795034287069726554">"Hiện thiết bị trên một màn hình ngoài"</item>
- <item msgid="5280431949814340475">"Hiện thiết bị trên màn hình được lấy tiêu điểm gần đây nhất"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 59d4b4d587ce..2763c017398b 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Đang sạc nhanh"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Do quản trị viên kiểm soát"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Do chế độ Cài đặt hạn chế kiểm soát"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Không dùng được khi có cuộc gọi"</string>
<string name="disabled" msgid="8017887509554714950">"Đã tắt"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Được phép"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Không được phép"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index c2147c7aba70..5c82865d3d52 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"仅设备显示屏(默认)"</item>
- <item msgid="9161645858025071955">"外接显示屏"</item>
- <item msgid="114384731934682483">"基于焦点"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"仅在设备显示屏上显示通知栏"</item>
- <item msgid="7795034287069726554">"在单个外接显示屏上显示设备"</item>
- <item msgid="5280431949814340475">"在最近一次获得焦点的显示屏上显示设备"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 08e931b80e1b..934c525661e5 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"正在快速充电"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"由管理员控制"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由受限设置控制"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"通话期间无法使用"</string>
<string name="disabled" msgid="8017887509554714950">"已停用"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"允许"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"不允许"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index 37d7b2930d3e..2e060595b299 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"只限裝置顯示屏 (預設)"</item>
- <item msgid="9161645858025071955">"外部顯示屏"</item>
- <item msgid="114384731934682483">"突顯"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"只在裝置顯示屏上顯示陰影"</item>
- <item msgid="7795034287069726554">"在單獨外部顯示屏上顯示裝置"</item>
- <item msgid="5280431949814340475">"在上一次突顯的顯示屏上顯示裝置"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 8cc65c86cc3e..037f531b7c02 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -506,7 +506,7 @@
<string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ 充電中"</string>
<string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - 在 <xliff:g id="TIME">%3$s</xliff:g>前充滿電"</string>
<string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> • 在 <xliff:g id="TIME">%2$s</xliff:g>前充滿電"</string>
- <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"在 <xliff:g id="TIME">%1$s</xliff:g>前充滿電"</string>
+ <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"在<xliff:g id="TIME">%1$s</xliff:g> 前充滿電"</string>
<string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"<xliff:g id="TIME">%1$s</xliff:g> 前充滿電"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"快速充電"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"已由管理員停用"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由「受限設定」控制"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"通話時無法使用"</string>
<string name="disabled" msgid="8017887509554714950">"已停用"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"允許"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"不允許"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index c4d820c50549..5b48ad40c63c 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"僅裝置螢幕 (預設)"</item>
- <item msgid="9161645858025071955">"外接螢幕"</item>
- <item msgid="114384731934682483">"使用中的螢幕"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"只在裝置螢幕顯示通知欄"</item>
- <item msgid="7795034287069726554">"在單一外接螢幕顯示通知欄"</item>
- <item msgid="5280431949814340475">"在最新使用的螢幕顯示通知欄"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"預設螢幕"</item>
- <item msgid="774789415968826925">"任何外接螢幕"</item>
- <item msgid="7880769915418638436">"最新觸控狀態列"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index d639e71f1a06..0ef65e6151d1 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"快速充電"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"已由管理員停用"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由受限制的設定控管"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"通話時無法使用"</string>
<string name="disabled" msgid="8017887509554714950">"已停用"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"允許"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"不允許"</string>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index 27ca40c4a66b..1a61f8b3d326 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -288,19 +288,10 @@
<item msgid="3753634915787796632">"2"</item>
<item msgid="4779928470672877922">"3"</item>
</string-array>
- <string-array name="shade_display_awareness_entries">
- <item msgid="816770658383209617">"Ukuboniswa kwedivayisi kuphela (Okuzenzakalelayo)"</item>
- <item msgid="9161645858025071955">"Ukubonisa Kwangaphandle"</item>
- <item msgid="114384731934682483">"Kusekelwe ekugxileni"</item>
- </string-array>
- <string-array name="shade_display_awareness_summaries">
- <item msgid="2964753205732912921">"Bonisa umthunzi esibonisini sedivayisi kuphela"</item>
- <item msgid="7795034287069726554">"Bonisa idivayisi esibonisini sangaphandle esisodwa"</item>
- <item msgid="5280431949814340475">"Bonisa idivayisi esibonisini sokugcina esigxilile"</item>
- </string-array>
- <string-array name="shade_display_awareness_values">
- <item msgid="3055776101992426514">"default_display"</item>
- <item msgid="774789415968826925">"any_external_display"</item>
- <item msgid="7880769915418638436">"status_bar_latest_touch"</item>
- </string-array>
+ <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) -->
+ <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) -->
+ <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) -->
+ <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) -->
+ <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) -->
+ <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) -->
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 4fd2c8d1e843..de626284ff87 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -523,8 +523,7 @@
<string name="battery_info_status_charging_fast_v2" msgid="1825439848151256589">"Ishaja ngokushesha"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kulawulwa umqondisi"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kulawulwe Isethingi Elikhawulelwe"</string>
- <!-- no translation found for disabled_in_phone_call_text (6568931334337318320) -->
- <skip />
+ <string name="disabled_in_phone_call_text" msgid="6568931334337318320">"Akutholakali ngesikhathi samakholi"</string>
<string name="disabled" msgid="8017887509554714950">"Akusebenzi"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"Kuvumelekile"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"Akuvumelekile"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a3e42f1d1e51..91ec83690722 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -236,6 +236,14 @@
<string name="bluetooth_active_media_only_battery_level">Active (media only). <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery.</string>
<!-- Connected devices settings. Message when Bluetooth is connected and active for media only, showing remote device status and battery level for untethered headset. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_media_only_battery_level_untethered">Active (media only). L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g>, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery.</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device status and battery level for temporary bond device. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_battery_level">Guest device. <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery.</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device status and battery level for temporary bond untethered headset. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_battery_level_untethered">Guest device. L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g>, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery.</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected and active for media only, showing remote device status and battery level for temporary bond device. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_media_only_battery_level">Guest device (media only). <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery.</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected and active for media only, showing remote device status and battery level for temporary bond untethered headset. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_media_only_battery_level_untethered">Guest device (media only). L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g>, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery.</string>
<!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level, supports audio sharing. [CHAR LIMIT=NONE] -->
<string name="bluetooth_battery_level_lea_support">Connected (supports audio sharing). <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery.</string>
<!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset, supports audio sharing. [CHAR LIMIT=NONE] -->
@@ -246,10 +254,22 @@
<string name="bluetooth_battery_level_untethered_right_lea_support">Connected (supports audio sharing). Right: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery.</string>
<!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing no battery information, supports audio sharing. [CHAR LIMIT=NONE] -->
<string name="bluetooth_no_battery_level_lea_support">Connected (supports audio sharing)</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level, supports audio sharing. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_battery_level_lea_support">Guest device (supports audio sharing). <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery.</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset, supports audio sharing. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_battery_level_untethered_lea_support">Guest device (supports audio sharing). L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g>, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery.</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing no battery information, supports audio sharing. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_no_battery_level_lea_support">Guest device (supports audio sharing)</string>
<!-- Connected devices settings. Message when Bluetooth is connected and active for media only but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_media_only_no_battery_level">Active (media only)</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use with no battery information, showing remote device status for temporary bond device. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_no_battery_level">Guest device</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected and active for media only but no battery information, showing remote device status for temporary bond device. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_media_only_no_battery_level">Guest device (media only)</string>
<!-- Connected devices settings. Message shown when bluetooth device is disconnected but is a known, previously connected device, supports audio sharing [CHAR LIMIT=NONE] -->
<string name="bluetooth_saved_device_lea_support">Supports audio sharing</string>
+ <!-- Connected devices settings. Message shown when temporary bond bluetooth device is disconnected but is a known, previously connected device, supports audio sharing [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_guest_saved_device_lea_support">Guest device. Supports audio sharing</string>
<!-- Connected device settings. Message when the left-side hearing aid device is active for media only. [CHAR LIMIT=NONE] -->
<string name="bluetooth_hearing_aid_media_only_left_active">Active (media only), left only</string>
@@ -869,6 +889,9 @@
<!-- Preference category for monitoring debugging development settings. [CHAR LIMIT=25] -->
<string name="debug_monitoring_category">Monitoring</string>
+ <!-- Preference category to alter window management settings, [CHAR LIMIT=50] -->
+ <string name="window_management_category">Window Management</string>
+
<!-- UI debug setting: always enable strict mode? [CHAR LIMIT=25] -->
<string name="strict_mode">Strict mode enabled</string>
<!-- UI debug setting: show strict mode summary [CHAR LIMIT=50] -->
@@ -1103,6 +1126,13 @@
<!-- Developer settings: text for the WebView provider selection toast shown if an invalid provider was chosen (i.e. the setting list was stale). [CHAR LIMIT=NONE] -->
<string name="select_webview_provider_toast_text">This choice is no longer valid. Try again.</string>
+ <!-- [CHAR LIMIT=50] Label for button to launch current WebView provider's DevTools (developer tools) UI -->
+ <string name="webview_launch_devtools_title">WebView DevTools</string>
+ <!-- [CHAR LIMIT=50] Error toast shown to user when no (current) WebView package is found (when trying to launch DevTools) -->
+ <string name="webview_launch_devtools_no_package">WebView package not found.</string>
+ <!-- [CHAR LIMIT=50] Error toast shown to user when DevTools (developer tools) activity could not be launched (despite there being a WebView package) -->
+ <string name="webview_launch_devtools_no_activity">Could not launch DevTools.</string>
+
<!-- Name of feature to change color setting for the display [CHAR LIMIT=60] -->
<string name="picture_color_mode">Picture color mode</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 7374f80fd9db..bb96041739eb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -16,8 +16,7 @@
package com.android.settingslib.bluetooth;
-import static com.android.settingslib.flags.Flags.enableSetPreferredTransportForLeAudioDevice;
-import static com.android.settingslib.flags.Flags.ignoreA2dpDisconnectionForAndroidAuto;
+import static com.android.settingslib.media.flags.Flags.enableTvMediaOutputDialog;
import android.annotation.CallbackExecutor;
import android.annotation.StringRes;
@@ -53,7 +52,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.settingslib.R;
import com.android.settingslib.Utils;
-import com.android.settingslib.media.flags.Flags;
+import com.android.settingslib.flags.Flags;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.AdaptiveOutlineDrawable;
@@ -264,7 +263,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
mHandler.removeMessages(profile.getProfileId());
if (profile.getConnectionPolicy(mDevice) >
BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
- if (ignoreA2dpDisconnectionForAndroidAuto()
+ if (Flags.ignoreA2dpDisconnectionForAndroidAuto()
&& profile instanceof A2dpProfile && isAndroidAuto()) {
Log.w(TAG,
"onProfileStateChanged(): Skip setting A2DP "
@@ -306,7 +305,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
mLocalNapRoleConnected = true;
}
}
- if (enableSetPreferredTransportForLeAudioDevice()
+ if (Flags.enableSetPreferredTransportForLeAudioDevice()
&& profile instanceof HidProfile) {
updatePreferredTransport();
}
@@ -322,7 +321,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
mLocalNapRoleConnected = false;
}
- if (enableSetPreferredTransportForLeAudioDevice()
+ if (Flags.enableSetPreferredTransportForLeAudioDevice()
&& profile instanceof LeAudioProfile) {
updatePreferredTransport();
}
@@ -1345,6 +1344,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
if (mBluetoothManager == null) {
mBluetoothManager = LocalBluetoothManager.getInstance(mContext, null);
}
+ boolean isTempBond = Flags.enableTemporaryBondDevicesUi()
+ && BluetoothUtils.isTemporaryBondDevice(getDevice());
if (BluetoothUtils.hasConnectedBroadcastSource(this, mBluetoothManager)) {
// Gets summary for the buds which are in the audio sharing.
int groupId = BluetoothUtils.getGroupId(this);
@@ -1363,14 +1364,23 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
shortSummary);
} else {
// The buds are not primary buds
- return getSummaryWithBatteryInfo(
- R.string.bluetooth_active_media_only_battery_level_untethered,
- R.string.bluetooth_active_media_only_battery_level,
- R.string.bluetooth_active_media_only_no_battery_level,
- leftBattery,
- rightBattery,
- batteryLevelPercentageString,
- shortSummary);
+ return isTempBond
+ ? getSummaryWithBatteryInfo(
+ R.string.bluetooth_guest_media_only_battery_level_untethered,
+ R.string.bluetooth_guest_media_only_battery_level,
+ R.string.bluetooth_guest_media_only_no_battery_level,
+ leftBattery,
+ rightBattery,
+ batteryLevelPercentageString,
+ shortSummary)
+ : getSummaryWithBatteryInfo(
+ R.string.bluetooth_active_media_only_battery_level_untethered,
+ R.string.bluetooth_active_media_only_battery_level,
+ R.string.bluetooth_active_media_only_no_battery_level,
+ leftBattery,
+ rightBattery,
+ batteryLevelPercentageString,
+ shortSummary);
}
} else {
// Gets summary for the buds which are not in the audio sharing.
@@ -1381,16 +1391,28 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
&& profile.isEnabled(getDevice()))) {
// The buds support le audio.
if (isConnected()) {
- return getSummaryWithBatteryInfo(
- R.string.bluetooth_battery_level_untethered_lea_support,
- R.string.bluetooth_battery_level_lea_support,
- R.string.bluetooth_no_battery_level_lea_support,
- leftBattery,
- rightBattery,
- batteryLevelPercentageString,
- shortSummary);
+ return isTempBond
+ ? getSummaryWithBatteryInfo(
+ R.string.bluetooth_guest_battery_level_untethered_lea_support,
+ R.string.bluetooth_guest_battery_level_lea_support,
+ R.string.bluetooth_guest_no_battery_level_lea_support,
+ leftBattery,
+ rightBattery,
+ batteryLevelPercentageString,
+ shortSummary)
+ : getSummaryWithBatteryInfo(
+ R.string.bluetooth_battery_level_untethered_lea_support,
+ R.string.bluetooth_battery_level_lea_support,
+ R.string.bluetooth_no_battery_level_lea_support,
+ leftBattery,
+ rightBattery,
+ batteryLevelPercentageString,
+ shortSummary);
} else {
- return mContext.getString(R.string.bluetooth_saved_device_lea_support);
+ return isTempBond
+ ? mContext.getString(
+ R.string.bluetooth_guest_saved_device_lea_support)
+ : mContext.getString(R.string.bluetooth_saved_device_lea_support);
}
}
}
@@ -1509,11 +1531,19 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
leftBattery = getLeftBatteryLevel();
rightBattery = getRightBatteryLevel();
+ boolean isTempBond = Flags.enableTemporaryBondDevicesUi()
+ && BluetoothUtils.isTemporaryBondDevice(getDevice());
// Set default string with battery level in device connected situation.
if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
- stringRes = R.string.bluetooth_battery_level_untethered;
+ stringRes =
+ isTempBond
+ ? R.string.bluetooth_guest_battery_level_untethered
+ : R.string.bluetooth_battery_level_untethered;
} else if (batteryLevelPercentageString != null && !shortSummary) {
- stringRes = R.string.bluetooth_battery_level;
+ stringRes =
+ isTempBond
+ ? R.string.bluetooth_guest_battery_level
+ : R.string.bluetooth_battery_level;
}
// Set active string in following device connected situation, also show battery
@@ -1529,11 +1559,20 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|| (mIsActiveDeviceA2dp && !isOnCall)
|| mIsActiveDeviceLeAudio) {
if (isTwsBatteryAvailable(leftBattery, rightBattery) && !shortSummary) {
- stringRes = R.string.bluetooth_active_battery_level_untethered;
+ stringRes =
+ isTempBond
+ ? R.string.bluetooth_guest_battery_level_untethered
+ : R.string.bluetooth_active_battery_level_untethered;
} else if (batteryLevelPercentageString != null && !shortSummary) {
- stringRes = R.string.bluetooth_active_battery_level;
+ stringRes =
+ isTempBond
+ ? R.string.bluetooth_guest_battery_level
+ : R.string.bluetooth_active_battery_level;
} else {
- stringRes = R.string.bluetooth_active_no_battery_level;
+ stringRes =
+ isTempBond
+ ? R.string.bluetooth_guest_no_battery_level
+ : R.string.bluetooth_active_no_battery_level;
}
}
@@ -1559,7 +1598,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|| stringRes == R.string.bluetooth_active_battery_level_untethered_left
|| stringRes == R.string.bluetooth_active_battery_level_untethered_right
|| stringRes == R.string.bluetooth_battery_level_untethered;
- if (isTvSummary && summaryIncludesBatteryLevel && Flags.enableTvMediaOutputDialog()) {
+ if (isTvSummary && summaryIncludesBatteryLevel && enableTvMediaOutputDialog()) {
return getTvBatterySummary(
getMinBatteryLevelWithMemberDevices(),
leftBattery,
@@ -1949,6 +1988,17 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
}
/**
+ * @return {@code true} if {@code cachedBluetoothDevice} has member which is LeAudio device
+ */
+ public boolean hasConnectedLeAudioMemberDevice() {
+ LeAudioProfile leAudio = mProfileManager.getLeAudioProfile();
+ return leAudio != null && getMemberDevice().stream().anyMatch(
+ cachedDevice -> cachedDevice != null && cachedDevice.getDevice() != null
+ && leAudio.getConnectionStatus(cachedDevice.getDevice())
+ == BluetoothProfile.STATE_CONNECTED);
+ }
+
+ /**
* @return {@code true} if {@code cachedBluetoothDevice} supports broadcast assistant profile
*/
public boolean isConnectedLeAudioBroadcastAssistantDevice() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index 51259e2f311d..e7887ed26cc3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -295,9 +295,9 @@ public class DreamBackend {
@WhenToDream
public int getWhenToDreamSetting() {
return isActivatedOnDock() && isActivatedOnSleep() ? WHILE_CHARGING_OR_DOCKED
- : isActivatedOnDock() ? WHILE_DOCKED
- : isActivatedOnPostured() ? WHILE_POSTURED
- : isActivatedOnSleep() ? WHILE_CHARGING
+ : isActivatedOnSleep() ? WHILE_CHARGING
+ : isActivatedOnDock() ? WHILE_DOCKED
+ : isActivatedOnPostured() ? WHILE_POSTURED
: NEVER;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
index 13a06017abbc..671dfa230f0d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
@@ -128,12 +128,20 @@ public class SignalDrawable extends DrawableWrapper {
@Override
public int getIntrinsicWidth() {
- return mIntrinsicSize;
+ if (newStatusBarIcons()) {
+ return super.getIntrinsicWidth();
+ } else {
+ return mIntrinsicSize;
+ }
}
@Override
public int getIntrinsicHeight() {
- return mIntrinsicSize;
+ if (newStatusBarIcons()) {
+ return super.getIntrinsicHeight();
+ } else {
+ return mIntrinsicSize;
+ }
}
private void updateAnimation() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
index 094567c400a3..9ca46238c2ce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
@@ -18,6 +18,7 @@ package com.android.settingslib.mobile;
import com.android.settingslib.R;
import com.android.settingslib.SignalIcon.MobileIconGroup;
+import com.android.settingslib.flags.Flags;
import java.util.HashMap;
import java.util.Map;
@@ -29,22 +30,47 @@ public class TelephonyIcons {
//***** Data connection icons
public static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
- public static final int ICON_LTE = R.drawable.ic_lte_mobiledata;
- public static final int ICON_LTE_PLUS = R.drawable.ic_lte_plus_mobiledata;
- public static final int ICON_G = R.drawable.ic_g_mobiledata;
- public static final int ICON_E = R.drawable.ic_e_mobiledata;
- public static final int ICON_H = R.drawable.ic_h_mobiledata;
- public static final int ICON_H_PLUS = R.drawable.ic_h_plus_mobiledata;
- public static final int ICON_3G = R.drawable.ic_3g_mobiledata;
- public static final int ICON_4G = R.drawable.ic_4g_mobiledata;
- public static final int ICON_4G_PLUS = R.drawable.ic_4g_plus_mobiledata;
- public static final int ICON_4G_LTE = R.drawable.ic_4g_lte_mobiledata;
- public static final int ICON_4G_LTE_PLUS = R.drawable.ic_4g_lte_plus_mobiledata;
- public static final int ICON_5G_E = R.drawable.ic_5g_e_mobiledata;
- public static final int ICON_1X = R.drawable.ic_1x_mobiledata;
- public static final int ICON_5G = R.drawable.ic_5g_mobiledata;
- public static final int ICON_5G_PLUS = R.drawable.ic_5g_plus_mobiledata;
- public static final int ICON_CWF = R.drawable.ic_carrier_wifi;
+ public static final int ICON_LTE =
+ flagged(R.drawable.ic_lte_mobiledata, R.drawable.ic_lte_mobiledata_updated);
+ public static final int ICON_LTE_PLUS =
+ flagged(R.drawable.ic_lte_plus_mobiledata, R.drawable.ic_lte_plus_mobiledata_updated);
+ public static final int ICON_G =
+ flagged(R.drawable.ic_g_mobiledata, R.drawable.ic_g_mobiledata_updated);
+ public static final int ICON_E =
+ flagged(R.drawable.ic_e_mobiledata, R.drawable.ic_e_mobiledata_updated);
+ public static final int ICON_H =
+ flagged(R.drawable.ic_h_mobiledata, R.drawable.ic_h_mobiledata_updated);
+ public static final int ICON_H_PLUS =
+ flagged(R.drawable.ic_h_plus_mobiledata, R.drawable.ic_h_plus_mobiledata_updated);
+ public static final int ICON_3G =
+ flagged(R.drawable.ic_3g_mobiledata, R.drawable.ic_3g_mobiledata_updated);
+ public static final int ICON_4G =
+ flagged(R.drawable.ic_4g_mobiledata, R.drawable.ic_4g_mobiledata_updated);
+ public static final int ICON_4G_PLUS =
+ flagged(R.drawable.ic_4g_plus_mobiledata, R.drawable.ic_4g_plus_mobiledata_updated);
+ public static final int ICON_4G_LTE =
+ flagged(R.drawable.ic_4g_lte_mobiledata, R.drawable.ic_4g_lte_mobiledata_updated);
+ public static final int ICON_4G_LTE_PLUS =
+ flagged(R.drawable.ic_4g_lte_plus_mobiledata,
+ R.drawable.ic_4g_lte_plus_mobiledata_updated);
+ public static final int ICON_5G_E =
+ flagged(R.drawable.ic_5g_e_mobiledata, R.drawable.ic_5g_e_mobiledata_updated);
+ public static final int ICON_1X =
+ flagged(R.drawable.ic_1x_mobiledata, R.drawable.ic_1x_mobiledata_updated);
+ public static final int ICON_5G =
+ flagged(R.drawable.ic_5g_mobiledata, R.drawable.ic_5g_mobiledata_updated);
+ public static final int ICON_5G_PLUS =
+ flagged(R.drawable.ic_5g_plus_mobiledata, R.drawable.ic_5g_plus_mobiledata_updated);
+ public static final int ICON_CWF =
+ flagged(R.drawable.ic_carrier_wifi, R.drawable.ic_carrier_wifi_updated);
+
+ /** Make it slightly more obvious which resource we are using */
+ private static int flagged(int oldIcon, int newIcon) {
+ if (Flags.newStatusBarIcons()) {
+ return newIcon;
+ }
+ return oldIcon;
+ }
public static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
"CARRIER_NETWORK_CHANGE",
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt
index f446bb8e32d1..c4e724554c04 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/ZenModeRepository.kt
@@ -93,10 +93,9 @@ class ZenModeRepositoryImpl(
IntentFilter().apply {
addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED)
addAction(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED)
- if (android.app.Flags.modesApi())
- addAction(
- NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED
- )
+ addAction(
+ NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED
+ )
},
/* broadcastPermission = */ null,
/* scheduler = */ backgroundHandler,
@@ -109,16 +108,13 @@ class ZenModeRepositoryImpl(
}
override val consolidatedNotificationPolicy: StateFlow<NotificationManager.Policy?> by lazy {
- if (android.app.Flags.modesApi())
- flowFromBroadcast(NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED) {
- // If available, get the value from extras to avoid a potential binder call.
- it?.extras?.getParcelable(EXTRA_NOTIFICATION_POLICY)
- ?: notificationManager.consolidatedNotificationPolicy
- }
- else
- flowFromBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED) {
- notificationManager.consolidatedNotificationPolicy
- }
+ flowFromBroadcast(NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED) {
+ // If available, get the value from extras to avoid a potential binder call.
+ it?.extras?.getParcelable(
+ EXTRA_NOTIFICATION_POLICY,
+ NotificationManager.Policy::class.java
+ ) ?: notificationManager.consolidatedNotificationPolicy
+ }
}
override val globalZenMode: StateFlow<Int?> by lazy {
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/EnableDndDialogFactory.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/EnableDndDialogFactory.java
index f0e7fb851d5f..52d62b6226b8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/EnableDndDialogFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/EnableDndDialogFactory.java
@@ -19,7 +19,6 @@ package com.android.settingslib.notification.modes;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AlertDialog;
-import android.app.Flags;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
@@ -42,8 +41,6 @@ import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.TextView;
-import androidx.annotation.Nullable;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.PhoneWindow;
import com.android.settingslib.R;
@@ -80,7 +77,6 @@ public class EnableDndDialogFactory {
private static final int SECONDS_MS = 1000;
private static final int MINUTES_MS = 60 * SECONDS_MS;
- @Nullable
private final EnableDndDialogMetricsLogger mMetricsLogger;
@VisibleForTesting
@@ -152,16 +148,10 @@ public class EnableDndDialogFactory {
Slog.d(TAG, "Invalid manual condition: " + tag.condition);
}
// always triggers priority-only dnd with chosen condition
- if (Flags.modesApi()) {
- mNotificationManager.setZenMode(
- Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
- getRealConditionId(tag.condition), TAG,
- /* fromUser= */ true);
- } else {
- mNotificationManager.setZenMode(
- Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
- getRealConditionId(tag.condition), TAG);
- }
+ mNotificationManager.setZenMode(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ getRealConditionId(tag.condition), TAG,
+ /* fromUser= */ true);
}
});
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java b/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java
index 6e64c597f5cc..34e08af18f93 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java
@@ -34,6 +34,8 @@ import com.android.settingslib.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import androidx.annotation.NonNull;
+
/**
* This class is used to create custom dialog with icon, title, message and custom view that are
* horizontally centered.
@@ -191,20 +193,52 @@ public class CustomDialogHelper {
}
/**
+ * Sets title of the dialog by string.
+ */
+ @NonNull public CustomDialogHelper setTitle(@NonNull CharSequence title) {
+ mDialogTitle.setText(title);
+ return this;
+ }
+
+ /**
+ * Sets title padding of the dialog.
+ */
+ @NonNull public CustomDialogHelper setTitlePadding(int left, int top, int right, int bottom) {
+ mDialogTitle.setPadding(left, top, right, bottom);
+ return this;
+ }
+
+ /**
* Sets message of the dialog.
*/
- public CustomDialogHelper setMessage(@StringRes int resid) {
+ @NonNull public CustomDialogHelper setMessage(@StringRes int resid) {
mDialogMessage.setText(resid);
return this;
}
/**
+ * Sets message of the dialog by string.
+ */
+ @NonNull public CustomDialogHelper setMessage(@NonNull CharSequence message) {
+ mDialogMessage.setText(message);
+ return this;
+ }
+
+ /**
* Sets message padding of the dialog.
*/
- public CustomDialogHelper setMessagePadding(int dp) {
+ @NonNull public CustomDialogHelper setMessagePadding(int dp) {
mDialogMessage.setPadding(dp, dp, dp, dp);
return this;
}
+ /**
+ * Sets message padding of the dialog.
+ */
+ @NonNull
+ public CustomDialogHelper setMessagePadding(int left, int top, int right, int bottom) {
+ mDialogMessage.setPadding(left, top, right, bottom);
+ return this;
+ }
/**
* Sets icon of the dialog.
@@ -215,6 +249,15 @@ public class CustomDialogHelper {
}
/**
+ * Sets icon padding of the dialog.
+ */
+ @NonNull
+ public CustomDialogHelper setIconPadding(int left, int top, int right, int bottom) {
+ mDialogIcon.setPadding(left, top, right, bottom);
+ return this;
+ }
+
+ /**
* Removes all views that were previously added to the custom layout part.
*/
public CustomDialogHelper clearCustomLayout() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index d933a1ced8bc..f6e26a7200ef 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -17,6 +17,7 @@ package com.android.settingslib.bluetooth;
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
import static com.android.settingslib.flags.Flags.FLAG_ENABLE_SET_PREFERRED_TRANSPORT_FOR_LE_AUDIO_DEVICE;
+import static com.android.settingslib.flags.Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI;
import static com.google.common.truth.Truth.assertThat;
@@ -78,11 +79,14 @@ public class CachedBluetoothDeviceTest {
private static final String TWS_BATTERY_RIGHT = "25";
private static final String TWS_LOW_BATTERY_THRESHOLD_LOW = "10";
private static final String TWS_LOW_BATTERY_THRESHOLD_HIGH = "25";
+ private static final String TEMP_BOND_METADATA =
+ "<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>";
private static final short RSSI_1 = 10;
private static final short RSSI_2 = 11;
private static final boolean JUSTDISCOVERED_1 = true;
private static final boolean JUSTDISCOVERED_2 = false;
private static final int LOW_BATTERY_COLOR = android.R.color.holo_red_dark;
+ private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
@Mock
private LocalBluetoothProfileManager mProfileManager;
@Mock
@@ -128,6 +132,7 @@ public class CachedBluetoothDeviceTest {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TV_MEDIA_OUTPUT_DIALOG);
mSetFlagsRule.enableFlags(FLAG_ENABLE_SET_PREFERRED_TRANSPORT_FOR_LE_AUDIO_DEVICE);
mSetFlagsRule.enableFlags(FLAG_ENABLE_LE_AUDIO_SHARING);
+ mSetFlagsRule.enableFlags(FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI);
mContext = RuntimeEnvironment.application;
mAudioManager = mContext.getSystemService(AudioManager.class);
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
@@ -2075,6 +2080,87 @@ public class CachedBluetoothDeviceTest {
}
@Test
+ public void getConnectionSummary_GuestDeviceBroadcastPrimary_activeDevice_returnActive() {
+ when(mBroadcast.isEnabled(any())).thenReturn(true);
+ when(mCachedDevice.getDevice()).thenReturn(mDevice);
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ when(mDevice.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
+ .thenReturn(TEMP_BOND_METADATA.getBytes());
+
+ List<Long> bisSyncState = new ArrayList<>();
+ bisSyncState.add(1L);
+ when(mLeBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState);
+ List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
+ sourceList.add(mLeBroadcastReceiveState);
+ when(mAssistant.getAllSources(any())).thenReturn(sourceList);
+
+ when(mCachedDevice.getGroupId()).thenReturn(1);
+ when(mCachedDevice.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(true);
+
+ assertThat(mCachedDevice.getConnectionSummary(false))
+ .isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
+ }
+
+ @Test
+ public void getConnectionSummary_GuestDeviceBroadcastSecondary_activeDevice_returnGuestMedia() {
+ when(mBroadcast.isEnabled(any())).thenReturn(true);
+ when(mCachedDevice.getDevice()).thenReturn(mDevice);
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
+ 1);
+ when(mDevice.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
+ .thenReturn(TEMP_BOND_METADATA.getBytes());
+
+ List<Long> bisSyncState = new ArrayList<>();
+ bisSyncState.add(1L);
+ when(mLeBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState);
+ List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
+ sourceList.add(mLeBroadcastReceiveState);
+ when(mAssistant.getAllSources(any())).thenReturn(sourceList);
+
+ when(mCachedDevice.getGroupId()).thenReturn(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+
+ assertThat(mCachedDevice.getConnectionSummary(false))
+ .isEqualTo(
+ mContext.getString(R.string.bluetooth_guest_media_only_no_battery_level));
+ }
+
+ @Test
+ public void getConnectionSummary_GuestDeviceSupportsBroadcastConnected_returnGuestSupportLe() {
+ when(mBroadcast.isEnabled(any())).thenReturn(true);
+ when(mCachedDevice.getDevice()).thenReturn(mDevice);
+ when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
+ when(mDevice.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
+ .thenReturn(TEMP_BOND_METADATA.getBytes());
+
+ when(mCachedDevice.getProfiles()).thenReturn(ImmutableList.of(mLeAudioProfile));
+ when(mCachedDevice.isConnected()).thenReturn(true);
+
+ assertThat(mCachedDevice.getConnectionSummary(false))
+ .isEqualTo(
+ mContext.getString(R.string.bluetooth_guest_no_battery_level_lea_support));
+ }
+
+ @Test
+ public void getConnectionSummary_GuestDeviceSupportsBroadcastNotConnected_returnSavedGuest() {
+ when(mBroadcast.isEnabled(any())).thenReturn(true);
+ when(mCachedDevice.getDevice()).thenReturn(mDevice);
+ when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
+ when(mDevice.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
+ .thenReturn(TEMP_BOND_METADATA.getBytes());
+
+ when(mCachedDevice.getProfiles()).thenReturn(ImmutableList.of(mLeAudioProfile));
+ when(mCachedDevice.isConnected()).thenReturn(false);
+
+ assertThat(mCachedDevice.getConnectionSummary(false))
+ .isEqualTo(mContext.getString(R.string.bluetooth_guest_saved_device_lea_support));
+ }
+
+ @Test
public void isHearingDevice_supportHearingRelatedProfiles_returnTrue() {
when(mCachedDevice.getProfiles()).thenReturn(
ImmutableList.of(mHapClientProfile, mHearingAidProfile));
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
index 00ae96cfab50..c21eb0ce777a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
@@ -16,6 +16,8 @@
package com.android.settingslib.dream;
+import static android.service.dreams.Flags.FLAG_ALLOW_DREAM_WHEN_POSTURED;
+
import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_DATE;
import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS;
import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_TIME;
@@ -28,6 +30,7 @@ import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import org.junit.After;
@@ -173,6 +176,58 @@ public final class DreamBackendTest {
.containsExactlyElementsIn(enabledComplications);
}
+ @Test
+ @EnableFlags(FLAG_ALLOW_DREAM_WHEN_POSTURED)
+ public void testChargingAndPosturedBothEnabled() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ 1
+ );
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ 1
+ );
+
+ assertThat(mBackend.getWhenToDreamSetting()).isEqualTo(DreamBackend.WHILE_CHARGING);
+ }
+
+ @Test
+ public void testChargingAndDockedBothEnabled() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ 1
+ );
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ 1
+ );
+
+ assertThat(mBackend.getWhenToDreamSetting()).isEqualTo(
+ DreamBackend.WHILE_CHARGING_OR_DOCKED);
+ }
+
+ @Test
+ @EnableFlags(FLAG_ALLOW_DREAM_WHEN_POSTURED)
+ public void testPosturedAndDockedBothEnabled() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
+ 1
+ );
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ 1
+ );
+
+ assertThat(mBackend.getWhenToDreamSetting()).isEqualTo(
+ DreamBackend.WHILE_DOCKED);
+ }
+
private void setControlsEnabledOnLockscreen(boolean enabled) {
Settings.Secure.putInt(
mContext.getContentResolver(),
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt
index 388af61c6273..b364368df473 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/data/repository/ZenModeRepositoryTest.kt
@@ -91,7 +91,6 @@ class ZenModeRepositoryTest {
)
}
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
@Test
fun consolidatedPolicyChanges_repositoryEmits_flagsOn() {
testScope.runTest {
@@ -110,7 +109,6 @@ class ZenModeRepositoryTest {
}
}
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
@Test
fun consolidatedPolicyChanges_repositoryEmitsFromExtras() {
testScope.runTest {
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 27a3cf1198b2..60fe15662980 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -124,6 +124,7 @@ public class SecureSettings {
Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT,
Settings.Secure.DOZE_ENABLED,
Settings.Secure.DOZE_ALWAYS_ON,
+ Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED,
Settings.Secure.DOZE_PICK_UP_GESTURE,
Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 9591b4354678..3d941e82727f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -184,6 +184,7 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.STATUS_BAR_SHOW_VIBRATE_ICON, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DOZE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DOZE_ALWAYS_ON, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DOZE_PICK_UP_GESTURE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DOZE_DOUBLE_TAP_GESTURE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DOZE_TAP_SCREEN_GESTURE, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 4f5203136bbc..ed11e12c32ff 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -209,7 +209,7 @@ public class SettingsHelper {
// Get datatype for B&R metrics logging.
String datatype = "";
- if (Flags.enableMetricsSettingsBackupAgents()) {
+ if (areAgentMetricsEnabled()) {
datatype = SettingsBackupRestoreKeys.getKeyFromUri(destination);
}
@@ -299,7 +299,7 @@ public class SettingsHelper {
contentValues.put(Settings.NameValueTable.NAME, name);
contentValues.put(Settings.NameValueTable.VALUE, value);
cr.insert(destination, contentValues);
- if (Flags.enableMetricsSettingsBackupAgents()) {
+ if (areAgentMetricsEnabled()) {
mBackupRestoreEventLogger.logItemsRestored(datatype, /* count= */ 1);
}
} catch (Exception e) {
@@ -308,7 +308,7 @@ public class SettingsHelper {
sendBroadcastSystemUI = false;
sendBroadcastAccessibility = false;
Log.e(TAG, "Failed to restore setting name: " + name + " + value: " + value, e);
- if (Flags.enableMetricsSettingsBackupAgents()) {
+ if (areAgentMetricsEnabled()) {
mBackupRestoreEventLogger.logItemsRestoreFailed(
datatype, /* count= */ 1, ERROR_FAILED_TO_RESTORE_SETTING);
}
@@ -785,12 +785,12 @@ public class SettingsHelper {
am.updatePersistentConfigurationWithAttribution(config, mContext.getOpPackageName(),
mContext.getAttributionTag());
- if (Flags.enableMetricsSettingsBackupAgents() && mBackupRestoreEventLogger != null) {
+ if (areAgentMetricsEnabled()) {
mBackupRestoreEventLogger
.logItemsRestored(SettingsBackupRestoreKeys.KEY_LOCALE, localeList.size());
}
} catch (RemoteException e) {
- if (Flags.enableMetricsSettingsBackupAgents() && mBackupRestoreEventLogger != null) {
+ if (areAgentMetricsEnabled()) {
mBackupRestoreEventLogger
.logItemsRestoreFailed(
SettingsBackupRestoreKeys.KEY_LOCALE,
@@ -817,4 +817,8 @@ public class SettingsHelper {
void setBackupRestoreEventLogger(BackupRestoreEventLogger backupRestoreEventLogger) {
mBackupRestoreEventLogger = backupRestoreEventLogger;
}
+
+ private boolean areAgentMetricsEnabled() {
+ return Flags.enableMetricsSettingsBackupAgents() && mBackupRestoreEventLogger != null;
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java
index 74fd828f97ea..274fd3593918 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java
@@ -124,6 +124,7 @@ final class WritableNamespacePrefixes {
"privacy",
"private_compute_services",
"profcollect_native_boot",
+ "profiling_testing",
"remote_auth",
"remote_key_provisioning_native",
"rollback",
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
index 62c03ddc42b9..cb3f54e3c6be 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
@@ -20,6 +20,8 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
+import android.app.backup.BackupAnnotations.OperationType;
+import android.app.backup.BackupRestoreEventLogger;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
@@ -60,11 +62,14 @@ public class SettingsHelperRestoreTest {
private static final float FLOAT_TOLERANCE = 0.01f;
private ContentResolver mContentResolver;
private SettingsHelper mSettingsHelper;
+ private BackupRestoreEventLogger mBackupRestoreEventLogger;
@Before
public void setUp() {
mContentResolver = mInterceptingContext.getContentResolver();
mSettingsHelper = new SettingsHelper(mInterceptingContext);
+ mBackupRestoreEventLogger = new BackupRestoreEventLogger(OperationType.RESTORE);
+ mSettingsHelper.setBackupRestoreEventLogger(mBackupRestoreEventLogger);
}
@After
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index ab031a4e0f28..d2931d9bc231 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -22,7 +22,7 @@
<string name="bugreport_finished_title" msgid="4429132808670114081">"Zpráva o chybě <xliff:g id="ID">#%d</xliff:g> byla vytvořena"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Přidávání podrobností do zprávy o chybě"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Čekejte prosím…"</string>
- <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Na telefonu se brzy zobrazí zpráva o chybě."</string>
+ <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Zpráva o chybě se brzy zobrazí na telefonu."</string>
<string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Zprávu o chybě můžete sdílet klepnutím"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Zprávu o chybě můžete sdílet klepnutím"</string>
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Přejetím můžete zprávu o chybě sdílet bez snímku obrazovky, nebo vyčkejte, než se snímek připraví"</string>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index 1ff4bbdcd9c0..0a605654845d 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -22,7 +22,7 @@
<string name="bugreport_finished_title" msgid="4429132808670114081">"Raport o błędzie <xliff:g id="ID">#%d</xliff:g> został zapisany"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodaję szczegóły do raportu o błędzie"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Czekaj..."</string>
- <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Raport o błędzie będzie pojawiał się na telefonie przez chwilę"</string>
+ <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Raport o błędzie za chwilę pojawi się na telefonie"</string>
<string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Wybierz, by udostępnić raport o błędzie"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Kliknij, by udostępnić raport o błędzie"</string>
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Wybierz, by udostępnić raport o błędzie bez zrzutu ekranu, lub poczekaj, aż zostanie on wygenerowany"</string>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index 76702d6ccba2..ab6d51a5511a 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -19,7 +19,7 @@
<string name="app_label" msgid="3701846017049540910">"Lupina"</string>
<string name="bugreport_notification_channel" msgid="2574150205913861141">"Poročila o napakah"</string>
<string name="bugreport_in_progress_title" msgid="4311705936714972757">"Poročilo o napaki <xliff:g id="ID">#%d</xliff:g> je v izdelavi"</string>
- <string name="bugreport_finished_title" msgid="4429132808670114081">"Poročilo o napaki <xliff:g id="ID">#%d</xliff:g> zajeto"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"Poročilo o napaki <xliff:g id="ID">#%d</xliff:g> je zajeto"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodajanje podrobnosti v poročilo o napakah"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Počakajte ..."</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Poročilo o napakah bo kmalu prikazano v telefonu"</string>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 19806e7cdf64..49cdec11e104 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -60,6 +60,7 @@ filegroup {
"src-release/**/*.kt",
"src-release/**/*.java",
],
+ path: "src-release",
visibility: ["//visibility:private"],
}
@@ -69,6 +70,7 @@ filegroup {
"src-debug/**/*.kt",
"src-debug/**/*.java",
],
+ path: "src-debug",
visibility: ["//visibility:private"],
}
@@ -315,11 +317,11 @@ filegroup {
"tests/src/**/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt",
"tests/src/**/systemui/statusbar/policy/WalletControllerImplTest.kt",
"tests/src/**/keyguard/ClockEventControllerTest.kt",
- "tests/src/**/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/BluetoothDetailsContentManagerTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogRepositoryTest.kt",
- "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt",
"tests/src/**/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt",
"tests/src/**/systemui/broadcast/UserBroadcastDispatcherTest.kt",
@@ -430,12 +432,21 @@ android_library {
],
}
-android_library {
- name: "SystemUI-core",
+filegroup {
+ name: "SystemUI-core-srcs",
srcs: [
"src/**/*.kt",
"src/**/*.java",
"src/**/I*.aidl",
+ ],
+ path: "src",
+ visibility: ["//visibility:private"],
+}
+
+android_library {
+ name: "SystemUI-core",
+ srcs: [
+ ":SystemUI-core-srcs",
":ReleaseJavaFiles",
"compose/features/src/**/*.kt",
"compose/facade/enabled/src/**/*.kt",
@@ -731,9 +742,7 @@ android_library {
srcs: [
"tests/src/**/*.kt",
"tests/src/**/*.java",
- "src/**/*.kt",
- "src/**/*.java",
- "src/**/I*.aidl",
+ ":SystemUI-core-srcs",
":ReleaseJavaFiles",
":SystemUI-tests-multivalent",
":SystemUI-tests-utils",
@@ -841,7 +850,7 @@ java_library {
"androidx.test.uiautomator_uiautomator",
"androidx.core_core-animation-testing",
"androidx.test.ext.junit",
- "inline-mockito-robolectric-prebuilt",
+ "inline-mockito5-robolectric-prebuilt",
"mockito-kotlin-nodeps",
"platform-parametric-runner-lib",
"SystemUICustomizationTestUtils",
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 236654deefb5..f5c0233d56b1 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -8,7 +8,6 @@ achalke@google.com
acul@google.com
adamcohen@google.com
aioana@google.com
-alexchau@google.com
alexflo@google.com
andonian@google.com
amiko@google.com
@@ -91,10 +90,8 @@ rahulbanerjee@google.com
rgl@google.com
roosa@google.com
saff@google.com
-samcackett@google.com
santie@google.com
shanh@google.com
-silvajordan@google.com
snoeberger@google.com
spdonghao@google.com
steell@google.com
@@ -106,7 +103,6 @@ thiruram@google.com
tracyzhou@google.com
tsuji@google.com
twickham@google.com
-uwaisashraf@google.com
vadimt@google.com
valiiftime@google.com
vanjan@google.com
@@ -121,3 +117,11 @@ yuandizhou@google.com
yurilin@google.com
yuzhechen@google.com
zakcohen@google.com
+
+# Overview eng team
+alexchau@google.com
+samcackett@google.com
+silvajordan@google.com
+uwaisashraf@google.com
+vinayjoglekar@google.com
+willosborn@google.com
diff --git a/packages/SystemUI/aconfig/Android.bp b/packages/SystemUI/aconfig/Android.bp
index 088ec136f24e..f5bff859269f 100644
--- a/packages/SystemUI/aconfig/Android.bp
+++ b/packages/SystemUI/aconfig/Android.bp
@@ -28,6 +28,7 @@ package {
"//frameworks/libs/systemui/tracinglib:__subpackages__",
"//frameworks/base/services/accessibility:__subpackages__",
"//frameworks/base/services/tests:__subpackages__",
+ "//packages/apps/Settings:__subpackages__",
"//platform_testing:__subpackages__",
"//vendor:__subpackages__",
"//cts:__subpackages__",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 910f71276376..29b578ae6e48 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -67,6 +67,13 @@ flag {
}
flag {
+ name: "notifications_redesign_guts"
+ namespace: "systemui"
+ description: "Notifications Redesign: Update the look of the notification guts (that appear on long press). This includes using the new cache for app icons."
+ bug: "394822197"
+}
+
+flag {
name: "notification_row_content_binder_refactor"
namespace: "systemui"
description: "Convert the NotificationContentInflater to Kotlin and restructure it to support modern views"
@@ -957,20 +964,30 @@ flag {
}
flag {
- name: "dedicated_notif_inflation_thread"
+ name: "bind_keyguard_media_visibility"
namespace: "systemui"
- description: "Create a separate background thread for inflating notifications"
- bug: "308967184"
+ description: "Binds Keyguard Media Controller Visibility to MediaContainerView"
+ bug: "298213983"
metadata {
purpose: PURPOSE_BUGFIX
}
}
flag {
- name: "bind_keyguard_media_visibility"
+ name: "use_notif_inflation_thread_for_footer"
namespace: "systemui"
- description: "Binds Keyguard Media Controller Visibility to MediaContainerView"
- bug: "298213983"
+ description: "use the @NotifInflation thread for FooterView and EmptyShadeView inflation"
+ bug: "375320642"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "use_notif_inflation_thread_for_row"
+ namespace: "systemui"
+ description: "use the @NotifInflation thread for ExpandableNotificationRow inflation"
+ bug: "375320642"
metadata {
purpose: PURPOSE_BUGFIX
}
@@ -1258,13 +1275,6 @@ flag {
}
flag {
- name: "glanceable_hub_back_action"
- namespace: "systemui"
- description: "Support back action from glanceable hub"
- bug: "382771533"
-}
-
-flag {
name: "dream_overlay_updated_font"
namespace: "systemui"
description: "Flag to enable updated font settings for dream overlay"
@@ -1987,6 +1997,16 @@ flag {
}
flag {
+ name: "hardware_color_styles"
+ namespace: "systemui"
+ description: "Enables loading initial colors based ion hardware color"
+ bug: "347286986"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "shade_launch_accessibility"
namespace: "systemui"
description: "Intercept accessibility focus events for the Shade during launch animations to avoid stray TalkBack events."
@@ -1997,6 +2017,16 @@ flag {
}
flag {
+ name: "expand_collapse_privacy_dialog"
+ namespace: "systemui"
+ description: "Add expand and collapse actions to accessibility, to allow announcement in TalkBack when state changes."
+ bug: "380161221"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "show_locked_by_your_watch_keyguard_indicator"
namespace: "systemui"
description: "Show a Locked by your watch indicator on the keyguard when the device is locked by the watch."
@@ -2016,3 +2046,23 @@ flag {
description: "Enables the clock fidget animation"
bug: "364664389"
}
+
+flag {
+ name: "notifications_launch_radius"
+ namespace: "systemui"
+ description: "Fixes a discrepancy in corner radius between expanding notification and opening window during launch animations."
+ bug: "396054791"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "skip_hide_sensitive_notif_animation"
+ namespace: "systemui"
+ description: "Skip hide sensitive notification animation when the showing layout is not changed."
+ bug: "390624334"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
index 65cd3c79cd16..444389fb26ea 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
@@ -36,6 +36,7 @@ import android.view.ViewGroupOverlay
import android.widget.FrameLayout
import com.android.internal.jank.Cuj.CujType
import com.android.internal.jank.InteractionJankMonitor
+import com.android.systemui.Flags
import java.util.LinkedList
import kotlin.math.min
import kotlin.math.roundToInt
@@ -58,7 +59,7 @@ open class GhostedViewTransitionAnimatorController
@JvmOverloads
constructor(
/** The view that will be ghosted and from which the background will be extracted. */
- private val ghostedView: View,
+ transitioningView: View,
/** The [CujType] associated to this launch animation. */
private val launchCujType: Int? = null,
@@ -75,11 +76,24 @@ constructor(
private val isEphemeral: Boolean = false,
private var interactionJankMonitor: InteractionJankMonitor =
InteractionJankMonitor.getInstance(),
+
+ /** [ViewTransitionRegistry] to store the mapping of transitioning view and its token */
+ private val transitionRegistry: IViewTransitionRegistry? =
+ if (Flags.decoupleViewControllerInAnimlib()) {
+ ViewTransitionRegistry.instance
+ } else {
+ null
+ }
) : ActivityTransitionAnimator.Controller {
override val isLaunching: Boolean = true
/** The container to which we will add the ghost view and expanding background. */
- override var transitionContainer = ghostedView.rootView as ViewGroup
+ override var transitionContainer: ViewGroup
+ get() = ghostedView.rootView as ViewGroup
+ set(_) {
+ // empty, should never be set to avoid memory leak
+ }
+
private val transitionContainerOverlay: ViewGroupOverlay
get() = transitionContainer.overlay
@@ -138,9 +152,33 @@ constructor(
}
}
+ /** [ViewTransitionToken] to be used for storing transitioning view in [transitionRegistry] */
+ private val transitionToken =
+ if (Flags.decoupleViewControllerInAnimlib()) {
+ ViewTransitionToken(transitioningView::class.java)
+ } else {
+ null
+ }
+
+ /** The view that will be ghosted and from which the background will be extracted */
+ private val ghostedView: View
+ get() =
+ if (Flags.decoupleViewControllerInAnimlib()) {
+ transitionRegistry?.getView(transitionToken!!)
+ } else {
+ _ghostedView
+ }!!
+
+ private val _ghostedView =
+ if (Flags.decoupleViewControllerInAnimlib()) {
+ null
+ } else {
+ transitioningView
+ }
+
init {
// Make sure the View we launch from implements LaunchableView to avoid visibility issues.
- if (ghostedView !is LaunchableView) {
+ if (transitioningView !is LaunchableView) {
throw IllegalArgumentException(
"A GhostedViewLaunchAnimatorController was created from a View that does not " +
"implement LaunchableView. This can lead to subtle bugs where the visibility " +
@@ -148,6 +186,10 @@ constructor(
)
}
+ if (Flags.decoupleViewControllerInAnimlib()) {
+ transitionRegistry?.register(transitionToken!!, transitioningView)
+ }
+
/** Find the first view with a background in [view] and its children. */
fun findBackground(view: View): Drawable? {
if (view.background != null) {
@@ -184,6 +226,7 @@ constructor(
if (TransitionAnimator.returnAnimationsEnabled()) {
ghostedView.removeOnAttachStateChangeListener(detachListener)
}
+ transitionToken?.let { token -> transitionRegistry?.unregister(token) }
}
/**
@@ -237,7 +280,7 @@ constructor(
val insets = backgroundInsets
val boundCorrections: Rect =
if (ghostedView is LaunchableView) {
- ghostedView.getPaddingForLaunchAnimation()
+ (ghostedView as LaunchableView).getPaddingForLaunchAnimation()
} else {
Rect()
}
@@ -387,8 +430,8 @@ constructor(
if (ghostedView is LaunchableView) {
// Restore the ghosted view visibility.
- ghostedView.setShouldBlockVisibilityChanges(false)
- ghostedView.onActivityLaunchAnimationEnd()
+ (ghostedView as LaunchableView).setShouldBlockVisibilityChanges(false)
+ (ghostedView as LaunchableView).onActivityLaunchAnimationEnd()
} else {
// Make the ghosted view visible. We ensure that the view is considered VISIBLE by
// accessibility by first making it INVISIBLE then VISIBLE (see b/204944038#comment17
@@ -398,7 +441,7 @@ constructor(
ghostedView.invalidate()
}
- if (isEphemeral) {
+ if (isEphemeral || Flags.decoupleViewControllerInAnimlib()) {
onDispose()
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt
new file mode 100644
index 000000000000..af3ca87bf788
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation
+
+import android.view.View
+
+/** Represents a Registry for holding a transitioning view mapped to a token */
+interface IViewTransitionRegistry {
+
+ /**
+ * Registers the transitioning [view] mapped to a [token]
+ *
+ * @param token The token corresponding to the transitioning view
+ * @param view The view undergoing transition
+ */
+ fun register(token: ViewTransitionToken, view: View)
+
+ /**
+ * Unregisters the transitioned view from its corresponding [token]
+ *
+ * @param token The token corresponding to the transitioning view
+ */
+ fun unregister(token: ViewTransitionToken)
+
+ /**
+ * Extracts a transitioning view from registry using its corresponding [token]
+ *
+ * @param token The token corresponding to the transitioning view
+ */
+ fun getView(token: ViewTransitionToken): View?
+
+ /**
+ * Return token mapped to the [view], if it is present in the registry
+ *
+ * @param view the transitioning view whose token we are requesting
+ * @return token associated with the [view] if present, else null
+ */
+ fun getViewToken(view: View): ViewTransitionToken?
+
+ /** Event call to run on registry update (on both [register] and [unregister]) */
+ fun onRegistryUpdate()
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index b9f9bc7e2daa..5b073e49192a 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -27,9 +27,8 @@ import android.graphics.fonts.FontVariationAxis
import android.text.Layout
import android.util.Log
import android.util.LruCache
-
-private const val DEFAULT_ANIMATION_DURATION: Long = 300
-private const val TYPEFACE_CACHE_MAX_ENTRIES = 5
+import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
@@ -76,6 +75,10 @@ class TypefaceVariantCacheImpl(var baseTypeface: Typeface, override val animatio
cache.put(fvar, it)
}
}
+
+ companion object {
+ private const val TYPEFACE_CACHE_MAX_ENTRIES = 5
+ }
}
/**
@@ -108,25 +111,12 @@ class TextAnimator(
private val typefaceCache: TypefaceVariantCache,
private val invalidateCallback: () -> Unit = {},
) {
- // Following two members are for mutable for testing purposes.
- public var textInterpolator = TextInterpolator(layout, typefaceCache)
- public var animator =
- ValueAnimator.ofFloat(1f).apply {
- duration = DEFAULT_ANIMATION_DURATION
- addUpdateListener {
- textInterpolator.progress = it.animatedValue as Float
- textInterpolator.linearProgress =
- it.currentPlayTime.toFloat() / it.duration.toFloat()
- invalidateCallback()
- }
- addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) = textInterpolator.rebase()
+ @VisibleForTesting var textInterpolator = TextInterpolator(layout, typefaceCache)
+ @VisibleForTesting var createAnimator: () -> ValueAnimator = { ValueAnimator.ofFloat(1f) }
- override fun onAnimationCancel(animation: Animator) = textInterpolator.rebase()
- }
- )
- }
+ var animator: ValueAnimator? = null
+
+ val fontVariationUtils = FontVariationUtils()
sealed class PositionedGlyph {
/** Mutable X coordinate of the glyph position relative from drawing offset. */
@@ -165,8 +155,6 @@ class TextAnimator(
protected set
}
- private val fontVariationUtils = FontVariationUtils()
-
fun updateLayout(layout: Layout, textSize: Float = -1f) {
textInterpolator.layout = layout
@@ -178,9 +166,8 @@ class TextAnimator(
}
}
- fun isRunning(): Boolean {
- return animator.isRunning
- }
+ val isRunning: Boolean
+ get() = animator?.isRunning ?: false
/**
* GlyphFilter applied just before drawing to canvas for tweaking positions and text size.
@@ -237,110 +224,110 @@ class TextAnimator(
fun draw(c: Canvas) = textInterpolator.draw(c)
- /**
- * Set text style with animation.
- *
- * ```
- * By passing -1 to weight, the view preserve the current weight.
- * By passing -1 to textSize, the view preserve the current text size.
- * By passing -1 to duration, the default text animation, 1000ms, is used.
- * By passing false to animate, the text will be updated without animation.
- * ```
- *
- * @param fvar an optional text fontVariationSettings.
- * @param textSize an optional font size.
- * @param colors an optional colors array that must be the same size as numLines passed to the
- * TextInterpolator
- * @param strokeWidth an optional paint stroke width
- * @param animate an optional boolean indicating true for showing style transition as animation,
- * false for immediate style transition. True by default.
- * @param duration an optional animation duration in milliseconds. This is ignored if animate is
- * false.
- * @param interpolator an optional time interpolator. If null is passed, last set interpolator
- * will be used. This is ignored if animate is false.
- */
- fun setTextStyle(
- fvar: String? = "",
- textSize: Float = -1f,
- color: Int? = null,
- strokeWidth: Float = -1f,
- animate: Boolean = true,
- duration: Long = -1L,
- interpolator: TimeInterpolator? = null,
- delay: Long = 0,
- onAnimationEnd: Runnable? = null,
+ /** Style spec to use when rendering the font */
+ data class Style(
+ val fVar: String? = null,
+ val textSize: Float? = null,
+ val color: Int? = null,
+ val strokeWidth: Float? = null,
) {
- setTextStyleInternal(
- fvar,
- textSize,
- color,
- strokeWidth,
- animate,
- duration,
- interpolator,
- delay,
- onAnimationEnd,
- updateLayoutOnFailure = true,
- )
+ fun withUpdatedFVar(
+ fontVariationUtils: FontVariationUtils,
+ weight: Int = -1,
+ width: Int = -1,
+ opticalSize: Int = -1,
+ roundness: Int = -1,
+ ): Style {
+ return this.copy(
+ fVar =
+ fontVariationUtils.updateFontVariation(
+ weight = weight,
+ width = width,
+ opticalSize = opticalSize,
+ roundness = roundness,
+ )
+ )
+ }
}
- private fun setTextStyleInternal(
- fvar: String?,
- textSize: Float,
- color: Int?,
- strokeWidth: Float,
- animate: Boolean,
- duration: Long,
- interpolator: TimeInterpolator?,
- delay: Long,
- onAnimationEnd: Runnable?,
- updateLayoutOnFailure: Boolean,
+ /** Animation Spec for use when style changes should be animated */
+ data class Animation(
+ val animate: Boolean = true,
+ val startDelay: Long = 0,
+ val duration: Long = DEFAULT_ANIMATION_DURATION,
+ val interpolator: TimeInterpolator = Interpolators.LINEAR,
+ val onAnimationEnd: Runnable? = null,
) {
- try {
- if (animate) {
- animator.cancel()
- textInterpolator.rebase()
+ fun configureAnimator(animator: Animator) {
+ animator.startDelay = startDelay
+ animator.duration = duration
+ animator.interpolator = interpolator
+ if (onAnimationEnd != null) {
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ onAnimationEnd.run()
+ }
+ }
+ )
}
+ }
- if (textSize >= 0) {
- textInterpolator.targetPaint.textSize = textSize
- }
- if (!fvar.isNullOrBlank()) {
- textInterpolator.targetPaint.typeface = typefaceCache.getTypefaceForVariant(fvar)
- }
- if (color != null) {
- textInterpolator.targetPaint.color = color
- }
- if (strokeWidth >= 0F) {
- textInterpolator.targetPaint.strokeWidth = strokeWidth
+ companion object {
+ val DISABLED = Animation(animate = false)
+ }
+ }
+
+ /** Sets the text style, optionally with animation */
+ fun setTextStyle(style: Style, animation: Animation = Animation.DISABLED) {
+ animator?.cancel()
+ setTextStyleInternal(style, rebase = animation.animate)
+
+ if (animation.animate) {
+ animator = buildAnimator(animation).apply { start() }
+ } else {
+ textInterpolator.progress = 1f
+ textInterpolator.rebase()
+ invalidateCallback()
+ }
+ }
+
+ /** Builds a ValueAnimator from the specified animation parameters */
+ private fun buildAnimator(animation: Animation): ValueAnimator {
+ return createAnimator().apply {
+ duration = DEFAULT_ANIMATION_DURATION
+ animation.configureAnimator(this)
+
+ addUpdateListener {
+ textInterpolator.progress = it.animatedValue as Float
+ textInterpolator.linearProgress = it.currentPlayTime / it.duration.toFloat()
+ invalidateCallback()
}
- textInterpolator.onTargetPaintModified()
- if (animate) {
- animator.startDelay = delay
- animator.duration = if (duration == -1L) DEFAULT_ANIMATION_DURATION else duration
- interpolator?.let { animator.interpolator = it }
- if (onAnimationEnd != null) {
- animator.addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- onAnimationEnd.run()
- animator.removeListener(this)
- }
-
- override fun onAnimationCancel(animation: Animator) {
- animator.removeListener(this)
- }
- }
- )
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animator: Animator) = textInterpolator.rebase()
+
+ override fun onAnimationCancel(animator: Animator) = textInterpolator.rebase()
}
- animator.start()
- } else {
- // No animation is requested, thus set base and target state to the same state.
- textInterpolator.progress = 1f
- textInterpolator.rebase()
- invalidateCallback()
+ )
+ }
+ }
+
+ private fun setTextStyleInternal(
+ style: Style,
+ rebase: Boolean,
+ updateLayoutOnFailure: Boolean = true,
+ ) {
+ try {
+ if (rebase) textInterpolator.rebase()
+ style.color?.let { textInterpolator.targetPaint.color = it }
+ style.textSize?.let { textInterpolator.targetPaint.textSize = it }
+ style.strokeWidth?.let { textInterpolator.targetPaint.strokeWidth = it }
+ style.fVar?.let {
+ textInterpolator.targetPaint.typeface = typefaceCache.getTypefaceForVariant(it)
}
+ textInterpolator.onTargetPaintModified()
} catch (ex: IllegalArgumentException) {
if (updateLayoutOnFailure) {
Log.e(
@@ -351,81 +338,15 @@ class TextAnimator(
)
updateLayout(textInterpolator.layout)
- setTextStyleInternal(
- fvar,
- textSize,
- color,
- strokeWidth,
- animate,
- duration,
- interpolator,
- delay,
- onAnimationEnd,
- updateLayoutOnFailure = false,
- )
+ setTextStyleInternal(style, rebase, updateLayoutOnFailure = false)
} else {
throw ex
}
}
}
- /**
- * Set text style with animation. Similar as
- *
- * ```
- * fun setTextStyle(
- * fvar: String? = "",
- * textSize: Float = -1f,
- * color: Int? = null,
- * strokeWidth: Float = -1f,
- * animate: Boolean = true,
- * duration: Long = -1L,
- * interpolator: TimeInterpolator? = null,
- * delay: Long = 0,
- * onAnimationEnd: Runnable? = null
- * )
- * ```
- *
- * @param weight an optional style value for `wght` in fontVariationSettings.
- * @param width an optional style value for `wdth` in fontVariationSettings.
- * @param opticalSize an optional style value for `opsz` in fontVariationSettings.
- * @param roundness an optional style value for `ROND` in fontVariationSettings.
- */
- fun setTextStyle(
- weight: Int = -1,
- width: Int = -1,
- opticalSize: Int = -1,
- roundness: Int = -1,
- textSize: Float = -1f,
- color: Int? = null,
- strokeWidth: Float = -1f,
- animate: Boolean = true,
- duration: Long = -1L,
- interpolator: TimeInterpolator? = null,
- delay: Long = 0,
- onAnimationEnd: Runnable? = null,
- ) {
- setTextStyleInternal(
- fvar =
- fontVariationUtils.updateFontVariation(
- weight = weight,
- width = width,
- opticalSize = opticalSize,
- roundness = roundness,
- ),
- textSize = textSize,
- color = color,
- strokeWidth = strokeWidth,
- animate = animate,
- duration = duration,
- interpolator = interpolator,
- delay = delay,
- onAnimationEnd = onAnimationEnd,
- updateLayoutOnFailure = true,
- )
- }
-
companion object {
private val TAG = TextAnimator::class.simpleName!!
+ const val DEFAULT_ANIMATION_DURATION = 300L
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt
index 58c2a1c98ec4..86c7f76c6bee 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt
@@ -24,14 +24,14 @@ import java.lang.ref.WeakReference
* A registry to temporarily store the view being transitioned into a Dialog (using
* [DialogTransitionAnimator]) or an Activity (using [ActivityTransitionAnimator])
*/
-class ViewTransitionRegistry {
+class ViewTransitionRegistry : IViewTransitionRegistry {
/**
* A map of a unique token to a WeakReference of the View being transitioned. WeakReference
* ensures that Views are garbage collected whenever they become eligible and avoid any
* memory leaks
*/
- private val registry by lazy { mutableMapOf<ViewTransitionToken, WeakReference<View>>() }
+ private val registry by lazy { mutableMapOf<ViewTransitionToken, WeakReference<View>>() }
/**
* A [View.OnAttachStateChangeListener] to be attached to all views stored in the registry to
@@ -45,8 +45,7 @@ class ViewTransitionRegistry {
}
override fun onViewDetachedFromWindow(view: View) {
- (view.getTag(R.id.tag_view_transition_token)
- as? ViewTransitionToken)?.let { token -> unregister(token) }
+ getViewToken(view)?.let { token -> unregister(token) }
}
}
}
@@ -57,12 +56,12 @@ class ViewTransitionRegistry {
* @param token unique token associated with the transitioning view
* @param view view undergoing transitions
*/
- fun register(token: ViewTransitionToken, view: View) {
+ override fun register(token: ViewTransitionToken, view: View) {
// token embedded as a view tag enables to use a single listener for all views
view.setTag(R.id.tag_view_transition_token, token)
view.addOnAttachStateChangeListener(listener)
registry[token] = WeakReference(view)
- emitCountForTrace()
+ onRegistryUpdate()
}
/**
@@ -70,30 +69,51 @@ class ViewTransitionRegistry {
*
* @param token unique token associated with the transitioning view
*/
- fun unregister(token: ViewTransitionToken) {
+ override fun unregister(token: ViewTransitionToken) {
registry.remove(token)?.let {
it.get()?.let { view ->
view.removeOnAttachStateChangeListener(listener)
view.setTag(R.id.tag_view_transition_token, null)
}
it.clear()
+ onRegistryUpdate()
}
- emitCountForTrace()
}
/**
* Access a view from registry using unique "token" associated with it
* WARNING - this returns a StrongReference to the View stored in the registry
*/
- fun getView(token: ViewTransitionToken): View? {
+ override fun getView(token: ViewTransitionToken): View? {
return registry[token]?.get()
}
/**
+ * Return token mapped to the [view], if it is present in the registry
+ *
+ * @param view the transitioning view whose token we are requesting
+ * @return token associated with the [view] if present, else null
+ */
+ override fun getViewToken(view: View): ViewTransitionToken? {
+ return (view.getTag(R.id.tag_view_transition_token) as? ViewTransitionToken)?.let { token ->
+ getView(token)?.let { token }
+ }
+ }
+
+ /** Event call to run on registry update (on both [register] and [unregister]) */
+ override fun onRegistryUpdate() {
+ emitCountForTrace()
+ }
+
+ /**
* Utility function to emit number of non-null views in the registry whenever the registry is
* updated (via [register] or [unregister])
*/
private fun emitCountForTrace() {
Trace.setCounter("transition_registry_view_count", registry.count().toLong())
}
+
+ companion object {
+ val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ViewTransitionRegistry() }
+ }
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionToken.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionToken.kt
index c211a8ed1de2..e011df01504f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionToken.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionToken.kt
@@ -16,17 +16,19 @@
package com.android.systemui.animation
+import java.util.UUID
+
/**
* A token uniquely mapped to a View in [ViewTransitionRegistry]. This token is guaranteed to be
* unique as timestamp is appended to the token string
*
- * @constructor creates an instance of [ViewTransitionToken] with token as "timestamp" or
- * "ClassName_timestamp"
+ * @constructor creates an instance of [ViewTransitionToken] with token as "UUID" or
+ * "ClassName_UUID"
*
* @property token String value of a unique token
*/
@JvmInline
value class ViewTransitionToken private constructor(val token: String) {
- constructor() : this(token = System.currentTimeMillis().toString())
- constructor(clazz: Class<*>) : this(token = clazz.simpleName + "_${System.currentTimeMillis()}")
+ constructor() : this(token = UUID.randomUUID().toString())
+ constructor(clazz: Class<*>) : this(token = clazz.simpleName + "_${UUID.randomUUID()}")
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/Icon.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/Icon.kt
index 8b0c00535262..09db2d653326 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/Icon.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/Icon.kt
@@ -19,10 +19,12 @@ package com.android.systemui.common.ui.compose
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.res.painterResource
-import com.android.compose.ui.graphics.painter.rememberDrawablePainter
+import androidx.core.graphics.drawable.toBitmap
import com.android.systemui.common.shared.model.Icon
/**
@@ -35,7 +37,12 @@ fun Icon(icon: Icon, modifier: Modifier = Modifier, tint: Color = LocalContentCo
val contentDescription = icon.contentDescription?.load()
when (icon) {
is Icon.Loaded -> {
- Icon(rememberDrawablePainter(icon.drawable), contentDescription, modifier, tint)
+ Icon(
+ remember(icon.drawable) { icon.drawable.toBitmap().asImageBitmap() },
+ contentDescription,
+ modifier,
+ tint,
+ )
}
is Icon.Resource -> Icon(painterResource(icon.res), contentDescription, modifier, tint)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 0b17a3f71bda..9b76f15b3cd6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -42,6 +42,7 @@ import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState
import com.android.compose.animation.scene.transitions
@@ -87,10 +88,26 @@ val sceneTransitionsV2 = transitions {
spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS)
fade(AllElements)
}
+ to(CommunalScenes.Communal, key = CommunalTransitionKeys.Swipe) {
+ spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS)
+ translate(Communal.Elements.Grid, Edge.End)
+ timestampRange(startMillis = 167, endMillis = 334) { fade(AllElements) }
+ }
to(CommunalScenes.Blank) {
spec = tween(durationMillis = TO_GONE_DURATION.toInt(DurationUnit.MILLISECONDS))
fade(AllElements)
}
+ to(CommunalScenes.Blank, key = CommunalTransitionKeys.Swipe) {
+ spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS)
+ translate(Communal.Elements.Grid, Edge.End)
+ timestampRange(endMillis = 167) {
+ fade(Communal.Elements.Grid)
+ fade(Communal.Elements.IndicationArea)
+ fade(Communal.Elements.LockIcon)
+ fade(Communal.Elements.StatusBar)
+ }
+ timestampRange(startMillis = 167, endMillis = 334) { fade(Communal.Elements.Scrim) }
+ }
}
val sceneTransitions = transitions {
@@ -165,6 +182,7 @@ fun CommunalContainer(
viewModel.communalBackground.collectAsStateWithLifecycle(
initialValue = CommunalBackgroundType.ANIMATED
)
+ val swipeToHubEnabled by viewModel.swipeToHubEnabled.collectAsStateWithLifecycle()
val state: MutableSceneTransitionLayoutState =
rememberMutableSceneTransitionLayoutState(
initialScene = currentSceneKey,
@@ -200,15 +218,27 @@ fun CommunalContainer(
scene(
CommunalScenes.Blank,
userActions =
- if (viewModel.swipeToHubEnabled())
- mapOf(Swipe.Start(fromSource = Edge.End) to CommunalScenes.Communal)
- else emptyMap(),
+ if (swipeToHubEnabled) {
+ mapOf(
+ Swipe.Start(fromSource = Edge.End) to
+ UserActionResult(CommunalScenes.Communal, CommunalTransitionKeys.Swipe)
+ )
+ } else {
+ emptyMap()
+ },
) {
// This scene shows nothing only allowing for transitions to the communal scene.
Box(modifier = Modifier.fillMaxSize())
}
- scene(CommunalScenes.Communal, userActions = mapOf(Swipe.End to CommunalScenes.Blank)) {
+ scene(
+ CommunalScenes.Communal,
+ userActions =
+ mapOf(
+ Swipe.End to
+ UserActionResult(CommunalScenes.Blank, CommunalTransitionKeys.Swipe)
+ ),
+ ) {
CommunalScene(
backgroundType = backgroundType,
colors = colors,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index ba85f9570d09..5806458da9b5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -20,11 +20,8 @@ import android.view.View
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
-import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
import com.android.internal.jank.Cuj
import com.android.internal.jank.Cuj.CujType
@@ -70,8 +67,7 @@ class LockscreenContent(
rememberViewModel("LockscreenContent-scrimViewModel") {
notificationScrimViewModelFactory.create()
}
- val isContentVisible: Boolean by viewModel.isContentVisible.collectAsStateWithLifecycle()
- if (!isContentVisible) {
+ if (!viewModel.isContentVisible) {
// If the content isn't supposed to be visible, show a large empty box as it's needed
// for scene transition animations (can't just skip rendering everything or shared
// elements won't have correct final/initial bounds from animating in and out of the
@@ -80,15 +76,13 @@ class LockscreenContent(
return
}
- val coroutineScope = rememberCoroutineScope()
- val blueprintId by viewModel.blueprintId(coroutineScope).collectAsStateWithLifecycle()
DisposableEffect(view) {
clockInteractor.clockEventController.registerListeners(view)
onDispose { clockInteractor.clockEventController.unregisterListeners() }
}
- val blueprint = blueprintByBlueprintId[blueprintId] ?: return
+ val blueprint = blueprintByBlueprintId[viewModel.blueprintId] ?: return
with(blueprint) {
Content(viewModel, modifier.sysuiResTag("keyguard_root_view"))
NotificationLockscreenScrim(notificationLockscreenScrimViewModel)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 6e25c8a5bc42..590a74ee2a0d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -23,7 +23,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
@@ -31,7 +30,7 @@ import androidx.compose.ui.layout.Layout
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntRect
-import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.padding
import com.android.systemui.compose.modifiers.sysuiResTag
@@ -44,6 +43,8 @@ import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.composable.section.TopAreaSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel.NotificationsPlacement.BelowClock
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel.NotificationsPlacement.BesideClock
import com.android.systemui.res.R
import java.util.Optional
import javax.inject.Inject
@@ -70,11 +71,8 @@ constructor(
@Composable
override fun ContentScope.Content(viewModel: LockscreenContentViewModel, modifier: Modifier) {
val isUdfpsVisible = viewModel.isUdfpsVisible
- val isShadeLayoutWide by viewModel.isShadeLayoutWide.collectAsStateWithLifecycle()
- val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
- val areNotificationsVisible by
- viewModel.areNotificationsVisible().collectAsStateWithLifecycle(initialValue = false)
- val isBypassEnabled by viewModel.isBypassEnabled.collectAsStateWithLifecycle()
+ val isBypassEnabled = viewModel.isBypassEnabled
+ val notificationsPlacement = viewModel.notificationsPlacement
if (isBypassEnabled) {
with(notificationSection) { HeadsUpNotifications() }
@@ -91,7 +89,9 @@ constructor(
modifier =
Modifier.fillMaxWidth()
.padding(
- horizontal = { unfoldTranslations.start.roundToInt() }
+ horizontal = {
+ viewModel.unfoldTranslations.start.roundToInt()
+ }
)
)
}
@@ -100,29 +100,29 @@ constructor(
with(topAreaSection) {
DefaultClockLayout(
smartSpacePaddingTop = viewModel::getSmartSpacePaddingTop,
- isShadeLayoutWide = isShadeLayoutWide,
modifier =
Modifier.fillMaxWidth().graphicsLayer {
- translationX = unfoldTranslations.start
+ translationX = viewModel.unfoldTranslations.start
},
)
}
- if (isShadeLayoutWide && !isBypassEnabled) {
+ if (notificationsPlacement is BesideClock && !isBypassEnabled) {
with(notificationSection) {
Box(modifier = Modifier.fillMaxHeight()) {
AodPromotedNotificationArea(
modifier =
Modifier.fillMaxWidth(0.5f)
- .align(alignment = Alignment.TopEnd)
+ .align(notificationsPlacement.alignment)
)
Notifications(
- areNotificationsVisible = areNotificationsVisible,
- isShadeLayoutWide = true,
+ areNotificationsVisible =
+ viewModel.areNotificationsVisible,
burnInParams = null,
modifier =
Modifier.fillMaxWidth(0.5f)
.fillMaxHeight()
- .align(alignment = Alignment.TopEnd),
+ .align(notificationsPlacement.alignment)
+ .padding(top = 12.dp),
)
}
}
@@ -137,7 +137,7 @@ constructor(
dimensionResource(R.dimen.below_clock_padding_start_icons)
with(notificationSection) {
- if (!isShadeLayoutWide && !isBypassEnabled) {
+ if (notificationsPlacement is BelowClock && !isBypassEnabled) {
Box(modifier = Modifier.weight(weight = 1f)) {
Column(Modifier.align(alignment = Alignment.TopStart)) {
AodPromotedNotificationArea(
@@ -149,14 +149,13 @@ constructor(
)
}
Notifications(
- areNotificationsVisible = areNotificationsVisible,
- isShadeLayoutWide = false,
+ areNotificationsVisible = viewModel.areNotificationsVisible,
burnInParams = null,
)
}
} else {
Column {
- if (!isShadeLayoutWide) {
+ if (viewModel.notificationsPlacement is BelowClock) {
AodPromotedNotificationArea(
modifier =
Modifier.padding(top = aodPromotedNotifTopPadding)
@@ -204,13 +203,17 @@ constructor(
isStart = true,
applyPadding = true,
modifier =
- Modifier.graphicsLayer { translationX = unfoldTranslations.start },
+ Modifier.graphicsLayer {
+ translationX = viewModel.unfoldTranslations.start
+ },
)
Shortcut(
isStart = false,
applyPadding = true,
modifier =
- Modifier.graphicsLayer { translationX = unfoldTranslations.end },
+ Modifier.graphicsLayer {
+ translationX = viewModel.unfoldTranslations.end
+ },
)
}
with(settingsMenuSection) { SettingsMenu(onSettingsMenuPlaced) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
index d8b3f742b447..0876631cf5c1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
@@ -41,16 +41,13 @@ constructor(
) {
@Composable
- fun ContentScope.KeyguardMediaCarousel(
- isShadeLayoutWide: Boolean,
- modifier: Modifier = Modifier,
- ) {
+ fun ContentScope.KeyguardMediaCarousel(modifier: Modifier = Modifier) {
val viewModel =
rememberViewModel(traceName = "KeyguardMediaCarousel") {
keyguardMediaViewModelFactory.create()
}
val horizontalPadding =
- if (isShadeLayoutWide) {
+ if (viewModel.isShadeLayoutWide) {
dimensionResource(id = R.dimen.notification_side_paddings)
} else {
dimensionResource(id = R.dimen.notification_side_paddings) +
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index f51049a10569..d903c3d16fdb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -18,12 +18,13 @@ package com.android.systemui.keyguard.ui.composable.section
import android.view.ViewGroup
import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.EnterTransition
+import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -31,11 +32,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
-import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
-import com.android.compose.modifiers.thenIf
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn
@@ -118,12 +117,19 @@ constructor(
val isVisible by
keyguardRootViewModel.isAodPromotedNotifVisible.collectAsStateWithLifecycle()
+ val transitionState = remember { MutableTransitionState(isVisible.value) }
+ LaunchedEffect(key1 = isVisible, key2 = transitionState.isIdle) {
+ transitionState.targetState = isVisible.value
+ if (isVisible.isAnimating && transitionState.isIdle) {
+ isVisible.stopAnimating()
+ }
+ }
val burnIn = rememberBurnIn(keyguardClockViewModel)
AnimatedVisibility(
- visible = isVisible,
- enter = fadeIn(),
- exit = fadeOut(),
+ visibleState = transitionState,
+ enter = if (isVisible.isAnimating) fadeIn() else EnterTransition.None,
+ exit = if (isVisible.isAnimating) fadeOut() else ExitTransition.None,
modifier = modifier.burnInAware(aodBurnInViewModel, burnIn.parameters),
) {
AODPromotedNotification(aodPromotedNotificationViewModelFactory)
@@ -186,7 +192,6 @@ constructor(
@Composable
fun ContentScope.Notifications(
areNotificationsVisible: Boolean,
- isShadeLayoutWide: Boolean,
burnInParams: BurnInParameters?,
modifier: Modifier = Modifier,
) {
@@ -198,16 +203,13 @@ constructor(
stackScrollView = stackScrollView.get(),
viewModel = rememberViewModel("Notifications") { viewModelFactory.create() },
modifier =
- modifier
- .fillMaxWidth()
- .thenIf(isShadeLayoutWide) { Modifier.padding(top = 12.dp) }
- .let {
- if (burnInParams == null) {
- it
- } else {
- it.burnInAware(viewModel = aodBurnInViewModel, params = burnInParams)
- }
- },
+ modifier.fillMaxWidth().let {
+ if (burnInParams == null) {
+ it
+ } else {
+ it.burnInAware(viewModel = aodBurnInViewModel, params = burnInParams)
+ }
+ },
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 6293fc26f96a..013424006668 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -60,7 +60,6 @@ constructor(
@Composable
fun ContentScope.DefaultClockLayout(
smartSpacePaddingTop: (Resources) -> Int,
- isShadeLayoutWide: Boolean,
modifier: Modifier = Modifier,
) {
val currentClockLayout by clockViewModel.currentClockLayout.collectAsStateWithLifecycle()
@@ -128,7 +127,7 @@ constructor(
)
}
}
- with(mediaCarouselSection) { KeyguardMediaCarousel(isShadeLayoutWide) }
+ with(mediaCarouselSection) { KeyguardMediaCarousel() }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
index 64f3cb13662a..297995becfb2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
@@ -23,7 +23,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.layout.layoutId
+import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.res.dimensionResource
import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
@@ -34,6 +34,13 @@ import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn
import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.media.controls.ui.composable.MediaCarousel
+import com.android.systemui.media.controls.ui.composable.isLandscape
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
+import com.android.systemui.media.controls.ui.view.MediaHost
+import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.COLLAPSED
+import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.EXPANDED
+import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayActionsViewModel
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel
import com.android.systemui.res.R
@@ -42,10 +49,11 @@ import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.ui.composable.Overlay
import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.composable.OverlayShadeHeader
-import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
+import com.android.systemui.util.Utils
import dagger.Lazy
import javax.inject.Inject
+import javax.inject.Named
import kotlinx.coroutines.flow.Flow
@SysUISingleton
@@ -58,6 +66,8 @@ constructor(
private val stackScrollView: Lazy<NotificationScrollView>,
private val clockSection: DefaultClockSection,
private val keyguardClockViewModel: KeyguardClockViewModel,
+ private val mediaCarouselController: MediaCarouselController,
+ @Named(QUICK_QS_PANEL) private val mediaHost: Lazy<MediaHost>,
) : Overlay {
override val key = Overlays.NotificationsShade
@@ -84,6 +94,11 @@ constructor(
viewModel.notificationsPlaceholderViewModelFactory.create()
}
+ val usingCollapsedLandscapeMedia =
+ Utils.useCollapsedMediaInLandscape(LocalResources.current)
+ mediaHost.get().expansion =
+ if (usingCollapsedLandscapeMedia && isLandscape()) COLLAPSED else EXPANDED
+
OverlayShade(
panelElement = NotificationsShade.Elements.Panel,
alignmentOnWideScreens = Alignment.TopStart,
@@ -96,9 +111,7 @@ constructor(
}
OverlayShadeHeader(
viewModel = headerViewModel,
- modifier =
- Modifier.element(NotificationsShade.Elements.StatusBar)
- .layoutId(SingleShadeMeasurePolicy.LayoutId.ShadeHeader),
+ modifier = Modifier.element(NotificationsShade.Elements.StatusBar),
)
},
) {
@@ -116,6 +129,19 @@ constructor(
}
}
+ MediaCarousel(
+ isVisible = viewModel.showMedia,
+ mediaHost = mediaHost.get(),
+ carouselController = mediaCarouselController,
+ usingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia,
+ modifier =
+ Modifier.padding(
+ top = notificationStackPadding,
+ start = notificationStackPadding,
+ end = notificationStackPadding,
+ ),
+ )
+
NotificationScrollingStack(
shadeSession = shadeSession,
stackScrollView = stackScrollView.get(),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
index 6d906bd4aa66..60eaa28e3822 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
@@ -21,6 +21,7 @@ import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
+import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.observableTransitionState
import com.android.systemui.scene.shared.model.SceneDataSource
import kotlinx.coroutines.CoroutineScope
@@ -68,7 +69,7 @@ class SceneTransitionLayoutDataSource(
}
override fun snapToScene(toScene: SceneKey) {
- state.snapToScene(scene = toScene)
+ state.snapTo(scene = toScene)
}
override fun showOverlay(overlay: OverlayKey, transitionKey: TransitionKey?) {
@@ -97,16 +98,14 @@ class SceneTransitionLayoutDataSource(
}
override fun instantlyShowOverlay(overlay: OverlayKey) {
- state.snapToScene(
- scene = state.transitionState.currentScene,
- currentOverlays = state.currentOverlays + overlay,
- )
+ state.snapTo(overlays = state.currentOverlays + overlay)
}
override fun instantlyHideOverlay(overlay: OverlayKey) {
- state.snapToScene(
- scene = state.transitionState.currentScene,
- currentOverlays = state.currentOverlays - overlay,
- )
+ state.snapTo(overlays = state.currentOverlays - overlay)
+ }
+
+ override fun freezeAndAnimateToCurrentState() {
+ (state.transitionState as? TransitionState.Transition)?.freezeAndAnimateToCurrentState()
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 5b275a556f93..56e8c458ad67 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -138,10 +138,13 @@ sealed interface MutableSceneTransitionLayoutState : SceneTransitionLayoutState
transitionKey: TransitionKey? = null,
): Pair<TransitionState.Transition, Job>?
- /** Immediately snap to the given [scene]. */
- fun snapToScene(
- scene: SceneKey,
- currentOverlays: Set<OverlayKey> = transitionState.currentOverlays,
+ /**
+ * Immediately snap to the given [scene] and/or [overlays], instantly interrupting all ongoing
+ * transitions and settling to a [TransitionState.Idle] state.
+ */
+ fun snapTo(
+ scene: SceneKey = transitionState.currentScene,
+ overlays: Set<OverlayKey> = transitionState.currentOverlays,
)
/**
@@ -554,7 +557,7 @@ internal class MutableSceneTransitionLayoutStateImpl(
this.transitionStates = listOf(idle)
}
- override fun snapToScene(scene: SceneKey, currentOverlays: Set<OverlayKey>) {
+ override fun snapTo(scene: SceneKey, overlays: Set<OverlayKey>) {
checkThread()
// Force finish all transitions.
@@ -562,7 +565,7 @@ internal class MutableSceneTransitionLayoutStateImpl(
check(transitionStates.size == 1)
check(currentTransitions.isEmpty())
- transitionStates = listOf(TransitionState.Idle(scene, currentOverlays))
+ transitionStates = listOf(TransitionState.Idle(scene, overlays))
}
override fun showOverlay(
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index fa10f66ab5a2..8fce7087dba6 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -247,7 +247,7 @@ class ElementTest {
rule.runOnUiThread {
// We snap to scene B so that the transition A => B is removed from the list of
// transitions.
- state.snapToScene(SceneB)
+ state.snapTo(SceneB)
state.setTargetScene(SceneC, coroutineScope)
}
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index 26f3c259dca9..eea6595cdf5e 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -255,7 +255,7 @@ class SceneTransitionLayoutStateTest {
assertThat(transition).hasCurrentScene(SceneB)
// Snap to C.
- state.snapToScene(SceneC)
+ state.snapTo(SceneC)
assertThat(state.transitionState).isIdle()
assertThat(state.transitionState).hasCurrentScene(SceneC)
}
@@ -272,7 +272,7 @@ class SceneTransitionLayoutStateTest {
assertThat(transition).hasToScene(SceneB)
// Snap to C.
- state.snapToScene(SceneC)
+ state.snapTo(SceneC)
assertThat(state.transitionState).isIdle()
assertThat(state.transitionState).hasCurrentScene(SceneC)
}
@@ -375,7 +375,7 @@ class SceneTransitionLayoutStateTest {
val job = transition.coroutineScope.launch { awaitCancellation() }
// Force snap state to SceneB to force finish all current transitions.
- state.snapToScene(SceneB)
+ state.snapTo(SceneB)
assertThat(state.transitionState).isIdle()
assertThat(job.isCancelled).isTrue()
}
@@ -411,7 +411,7 @@ class SceneTransitionLayoutStateTest {
val state = MutableSceneTransitionLayoutStateForTests(SceneA)
state.startTransitionImmediately(this, transition(SceneA, SceneB))
state.startTransitionImmediately(this, transition(SceneB, SceneC))
- state.snapToScene(SceneC)
+ state.snapTo(SceneC)
assertThat(state.transitionState).isIdle()
assertThat(state.transitionState).hasCurrentScene(SceneC)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index c877d99a77d3..5cbc98fa4c9d 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -457,9 +457,9 @@ class SceneTransitionLayoutTest {
}
// Snap to B then C to compose these scenes at least once.
- rule.runOnUiThread { state.snapToScene(SceneB) }
+ rule.runOnUiThread { state.snapTo(SceneB) }
rule.waitForIdle()
- rule.runOnUiThread { state.snapToScene(SceneC) }
+ rule.runOnUiThread { state.snapTo(SceneC) }
rule.waitForIdle()
assertThat(keyInA).isEqualTo(SceneA)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index b76656d78cc4..4bf0ceb51784 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -366,7 +366,7 @@ constructor(
fun animateCharge(isDozing: () -> Boolean) {
// Skip charge animation if dozing animation is already playing.
- if (textAnimator == null || textAnimator!!.isRunning()) {
+ if (textAnimator == null || textAnimator!!.isRunning) {
return
}
@@ -444,29 +444,28 @@ constructor(
delay: Long,
onAnimationEnd: Runnable?,
) {
- textAnimator?.let {
- it.setTextStyle(
- weight = weight,
- color = color,
+ val style = TextAnimator.Style(color = color)
+ val animation =
+ TextAnimator.Animation(
animate = animate && isAnimationEnabled,
duration = duration,
- interpolator = interpolator,
- delay = delay,
+ interpolator = interpolator ?: Interpolators.LINEAR,
+ startDelay = delay,
onAnimationEnd = onAnimationEnd,
)
+ textAnimator?.let {
+ it.setTextStyle(
+ style.withUpdatedFVar(it.fontVariationUtils, weight = weight),
+ animation,
+ )
it.glyphFilter = glyphFilter
}
?: run {
// when the text animator is set, update its start values
onTextAnimatorInitialized = { textAnimator ->
textAnimator.setTextStyle(
- weight = weight,
- color = color,
- animate = false,
- duration = duration,
- interpolator = interpolator,
- delay = delay,
- onAnimationEnd = onAnimationEnd,
+ style.withUpdatedFVar(textAnimator.fontVariationUtils, weight = weight),
+ animation.copy(animate = false),
)
textAnimator.glyphFilter = glyphFilter
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
index a5adfa2a1ac6..0b7ea1a335ef 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
@@ -21,6 +21,7 @@ import android.view.ViewGroup
import android.view.animation.Interpolator
import android.widget.RelativeLayout
import androidx.annotation.VisibleForTesting
+import com.android.systemui.animation.TextAnimator
import com.android.systemui.customization.R
import com.android.systemui.log.core.Logger
import com.android.systemui.plugins.clocks.AlarmData
@@ -65,7 +66,7 @@ data class DigitalAlignment(
data class FontTextStyle(
val lineHeight: Float? = null,
val fontSizeScale: Float? = null,
- val transitionDuration: Long = -1L,
+ val transitionDuration: Long = TextAnimator.DEFAULT_ANIMATION_DURATION,
val transitionInterpolator: Interpolator? = null,
)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
index b9a5f1f18210..8317aa39ef2b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
@@ -33,7 +33,9 @@ import android.util.MathUtils
import android.util.TypedValue
import android.view.View.MeasureSpec.EXACTLY
import android.view.animation.Interpolator
+import android.view.animation.PathInterpolator
import android.widget.TextView
+import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.GSFAxes
import com.android.systemui.animation.TextAnimator
@@ -84,17 +86,20 @@ open class SimpleDigitalClockTextView(
else -> listOf(FLEX_AOD_SMALL_WEIGHT_AXIS, FLEX_AOD_WIDTH_AXIS)
}
- private var lsFontVariation =
- if (!isLegacyFlex) listOf(LS_WEIGHT_AXIS, WIDTH_AXIS, ROUND_AXIS, SLANT_AXIS).toFVar()
- else listOf(FLEX_LS_WEIGHT_AXIS, FLEX_LS_WIDTH_AXIS, FLEX_ROUND_AXIS, SLANT_AXIS).toFVar()
+ private var lsFontVariation: String
+ private var aodFontVariation: String
+ private var fidgetFontVariation: String
- private var aodFontVariation = run {
+ init {
val roundAxis = if (!isLegacyFlex) ROUND_AXIS else FLEX_ROUND_AXIS
- (fixedAodAxes + listOf(roundAxis, SLANT_AXIS)).toFVar()
- }
+ val lsFontAxes =
+ if (!isLegacyFlex) listOf(LS_WEIGHT_AXIS, WIDTH_AXIS, ROUND_AXIS, SLANT_AXIS)
+ else listOf(FLEX_LS_WEIGHT_AXIS, FLEX_LS_WIDTH_AXIS, FLEX_ROUND_AXIS, SLANT_AXIS)
- // TODO(b/374306512): Fidget endpoint to spec
- private var fidgetFontVariation = aodFontVariation
+ lsFontVariation = lsFontAxes.toFVar()
+ aodFontVariation = (fixedAodAxes + listOf(roundAxis, SLANT_AXIS)).toFVar()
+ fidgetFontVariation = buildFidgetVariation(lsFontAxes).toFVar()
+ }
private val parser = DimensionParser(clockCtx.context)
var maxSingleDigitHeight = -1
@@ -121,7 +126,7 @@ open class SimpleDigitalClockTextView(
protected val logger = ClockLogger(this, clockCtx.messageBuffer, this::class.simpleName!!)
get() = field ?: ClockLogger.INIT_LOGGER
- private var aodDozingInterpolator: Interpolator? = null
+ private var aodDozingInterpolator: Interpolator = Interpolators.LINEAR
@VisibleForTesting lateinit var textAnimator: TextAnimator
@@ -149,7 +154,7 @@ open class SimpleDigitalClockTextView(
lockscreenColor = color
lockScreenPaint.color = lockscreenColor
if (dozeFraction < 1f) {
- textAnimator.setTextStyle(color = lockscreenColor, animate = false)
+ textAnimator.setTextStyle(TextAnimator.Style(color = lockscreenColor))
}
invalidate()
}
@@ -157,10 +162,8 @@ open class SimpleDigitalClockTextView(
fun updateAxes(lsAxes: List<ClockFontAxisSetting>) {
lsFontVariation = lsAxes.toFVar()
aodFontVariation = lsAxes.replace(fixedAodAxes).toFVar()
- logger.i({ "updateAxes(LS = $str1, AOD = $str2)" }) {
- str1 = lsFontVariation
- str2 = aodFontVariation
- }
+ fidgetFontVariation = buildFidgetVariation(lsAxes).toFVar()
+ logger.updateAxes(lsFontVariation, aodFontVariation)
lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation)
typeface = lockScreenPaint.typeface
@@ -168,13 +171,28 @@ open class SimpleDigitalClockTextView(
lockScreenPaint.getTextBounds(text, 0, text.length, textBounds)
targetTextBounds.set(textBounds)
- textAnimator.setTextStyle(fvar = lsFontVariation, animate = false)
+ textAnimator.setTextStyle(TextAnimator.Style(fVar = lsFontVariation))
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
recomputeMaxSingleDigitSizes()
requestLayout()
invalidate()
}
+ fun buildFidgetVariation(axes: List<ClockFontAxisSetting>): List<ClockFontAxisSetting> {
+ val result = mutableListOf<ClockFontAxisSetting>()
+ for (axis in axes) {
+ result.add(
+ FIDGET_DISTS.get(axis.key)?.let { (dist, midpoint) ->
+ ClockFontAxisSetting(
+ axis.key,
+ axis.value + dist * if (axis.value > midpoint) -1 else 1,
+ )
+ } ?: axis
+ )
+ }
+ return result
+ }
+
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
logger.onMeasure()
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
@@ -197,43 +215,12 @@ open class SimpleDigitalClockTextView(
)
}
- var expectedWidth: Int
- var expectedHeight: Int
-
- if (MeasureSpec.getMode(heightMeasureSpec) == EXACTLY) {
- // For view which has fixed height, e.g. small clock,
- // we should always return the size required from parent view
- expectedHeight = heightMeasureSpec
- } else {
- expectedHeight =
- MeasureSpec.makeMeasureSpec(
- if (isSingleDigit()) {
- maxSingleDigitHeight
- } else {
- textBounds.height() + 2 * lockScreenPaint.strokeWidth.toInt()
- },
- MeasureSpec.getMode(measuredHeightAndState),
- )
- }
-
- if (MeasureSpec.getMode(widthMeasureSpec) == EXACTLY) {
- expectedWidth = widthMeasureSpec
- } else {
- expectedWidth =
- MeasureSpec.makeMeasureSpec(
- if (isSingleDigit()) {
- maxSingleDigitWidth
- } else {
- max(
- textBounds.width() + 2 * lockScreenPaint.strokeWidth.toInt(),
- MeasureSpec.getSize(measuredWidthAndState),
- )
- },
- MeasureSpec.getMode(measuredWidthAndState),
- )
- }
-
- setMeasuredDimension(expectedWidth, expectedHeight)
+ setInterpolatedViewBounds(
+ getInterpolatedTextBounds(),
+ widthMeasureSpec,
+ heightMeasureSpec,
+ force = true,
+ )
}
override fun onDraw(canvas: Canvas) {
@@ -276,40 +263,54 @@ open class SimpleDigitalClockTextView(
fun animateDoze(isDozing: Boolean, isAnimated: Boolean) {
if (!this::textAnimator.isInitialized) return
+ logger.animateDoze()
textAnimator.setTextStyle(
- animate = isAnimated && isAnimationEnabled,
- color = if (isDozing) AOD_COLOR else lockscreenColor,
- textSize = if (isDozing) aodFontSizePx else lockScreenPaint.textSize,
- fvar = if (isDozing) aodFontVariation else lsFontVariation,
- duration = aodStyle.transitionDuration,
- interpolator = aodDozingInterpolator,
+ TextAnimator.Style(
+ fVar = if (isDozing) aodFontVariation else lsFontVariation,
+ color = if (isDozing) AOD_COLOR else lockscreenColor,
+ textSize = if (isDozing) aodFontSizePx else lockScreenPaint.textSize,
+ ),
+ TextAnimator.Animation(
+ animate = isAnimated && isAnimationEnabled,
+ duration = aodStyle.transitionDuration,
+ interpolator = aodDozingInterpolator,
+ ),
)
updateTextBoundsForTextAnimator()
}
fun animateCharge() {
- if (!this::textAnimator.isInitialized || textAnimator.isRunning()) {
+ if (!this::textAnimator.isInitialized || textAnimator.isRunning) {
// Skip charge animation if dozing animation is already playing.
return
}
- logger.d("animateCharge()")
+ logger.animateCharge()
+
+ val lsStyle = TextAnimator.Style(fVar = lsFontVariation)
+ val aodStyle = TextAnimator.Style(fVar = aodFontVariation)
+
textAnimator.setTextStyle(
- fvar = if (dozeFraction == 0F) aodFontVariation else lsFontVariation,
- animate = isAnimationEnabled,
- onAnimationEnd =
- Runnable {
+ if (dozeFraction == 0f) aodStyle else lsStyle,
+ TextAnimator.Animation(
+ animate = isAnimationEnabled,
+ duration = CHARGE_ANIMATION_DURATION,
+ onAnimationEnd = {
textAnimator.setTextStyle(
- fvar = if (dozeFraction == 0F) lsFontVariation else aodFontVariation,
- animate = isAnimationEnabled,
+ if (dozeFraction == 0f) lsStyle else aodStyle,
+ TextAnimator.Animation(
+ animate = isAnimationEnabled,
+ duration = CHARGE_ANIMATION_DURATION,
+ ),
)
updateTextBoundsForTextAnimator()
},
+ ),
)
updateTextBoundsForTextAnimator()
}
fun animateFidget(x: Float, y: Float) {
- if (!this::textAnimator.isInitialized || textAnimator.isRunning()) {
+ if (!this::textAnimator.isInitialized || textAnimator.isRunning) {
// Skip fidget animation if other animation is already playing.
return
}
@@ -317,19 +318,25 @@ open class SimpleDigitalClockTextView(
logger.animateFidget(x, y)
clockCtx.vibrator?.vibrate(FIDGET_HAPTICS)
- // TODO(b/374306512): Duplicated charge animation as placeholder. Implement final version
- // when we have a complete spec. May require additional code to animate individual digits.
+ // TODO(b/374306512): Delay each glyph's animation based on x/y position
textAnimator.setTextStyle(
- fvar = fidgetFontVariation,
- animate = isAnimationEnabled,
- onAnimationEnd =
- Runnable {
+ TextAnimator.Style(fVar = fidgetFontVariation),
+ TextAnimator.Animation(
+ animate = isAnimationEnabled,
+ duration = FIDGET_ANIMATION_DURATION,
+ interpolator = FIDGET_INTERPOLATOR,
+ onAnimationEnd = {
textAnimator.setTextStyle(
- fvar = if (dozeFraction == 0F) lsFontVariation else aodFontVariation,
- animate = isAnimationEnabled,
+ TextAnimator.Style(fVar = lsFontVariation),
+ TextAnimator.Animation(
+ animate = isAnimationEnabled,
+ duration = FIDGET_ANIMATION_DURATION,
+ interpolator = FIDGET_INTERPOLATOR,
+ ),
)
updateTextBoundsForTextAnimator()
},
+ ),
)
updateTextBoundsForTextAnimator()
}
@@ -359,47 +366,62 @@ open class SimpleDigitalClockTextView(
id == R.id.MINUTE_SECOND_DIGIT
}
- private fun updateInterpolatedTextBounds(): Rect {
+ private fun getInterpolatedTextBounds(): Rect {
+ val progress = textAnimator.animator?.let { it.animatedValue as Float } ?: 1f
+ if (!textAnimator.isRunning || progress >= 1f) {
+ return Rect(targetTextBounds)
+ }
+
val interpolatedTextBounds = Rect()
- if (textAnimator.animator.animatedFraction != 1.0f && textAnimator.animator.isRunning) {
- interpolatedTextBounds.left =
- MathUtils.lerp(
- prevTextBounds.left,
- targetTextBounds.left,
- textAnimator.animator.animatedValue as Float,
- )
- .toInt()
+ interpolatedTextBounds.left =
+ MathUtils.lerp(prevTextBounds.left, targetTextBounds.left, progress).toInt()
+ interpolatedTextBounds.right =
+ MathUtils.lerp(prevTextBounds.right, targetTextBounds.right, progress).toInt()
+ interpolatedTextBounds.top =
+ MathUtils.lerp(prevTextBounds.top, targetTextBounds.top, progress).toInt()
+ interpolatedTextBounds.bottom =
+ MathUtils.lerp(prevTextBounds.bottom, targetTextBounds.bottom, progress).toInt()
+ return interpolatedTextBounds
+ }
- interpolatedTextBounds.right =
- MathUtils.lerp(
- prevTextBounds.right,
- targetTextBounds.right,
- textAnimator.animator.animatedValue as Float,
- )
- .toInt()
+ private fun setInterpolatedViewBounds(
+ interpBounds: Rect,
+ widthMeasureSpec: Int = measuredWidthAndState,
+ heightMeasureSpec: Int = measuredHeightAndState,
+ force: Boolean = false,
+ ) {
+ val heightMode = MeasureSpec.getMode(heightMeasureSpec)
+ val widthMode = MeasureSpec.getMode(widthMeasureSpec)
+
+ val heightSpec =
+ if (heightMode == EXACTLY) {
+ heightMeasureSpec
+ } else {
+ MeasureSpec.makeMeasureSpec(
+ if (isSingleDigit()) maxSingleDigitHeight
+ else interpBounds.height() + 2 * lockScreenPaint.strokeWidth.toInt(),
+ heightMode,
+ )
+ }
- interpolatedTextBounds.top =
- MathUtils.lerp(
- prevTextBounds.top,
- targetTextBounds.top,
- textAnimator.animator.animatedValue as Float,
- )
- .toInt()
+ val widthSpec =
+ if (widthMode == EXACTLY) {
+ widthMeasureSpec
+ } else {
+ MeasureSpec.makeMeasureSpec(
+ if (isSingleDigit()) maxSingleDigitWidth
+ else interpBounds.width() + 2 * lockScreenPaint.strokeWidth.toInt(),
+ widthMode,
+ )
+ }
- interpolatedTextBounds.bottom =
- MathUtils.lerp(
- prevTextBounds.bottom,
- targetTextBounds.bottom,
- textAnimator.animator.animatedValue as Float,
- )
- .toInt()
- } else {
- interpolatedTextBounds.set(targetTextBounds)
+ if (force || widthSpec != measuredWidthAndState || heightSpec != measuredHeightAndState) {
+ setMeasuredDimension(widthSpec, heightSpec)
+ parent?.requestLayout()
}
- return interpolatedTextBounds
}
- private fun updateXtranslation(inPoint: Point, interpolatedTextBounds: Rect): Point {
+ private fun updateXTranslation(inPoint: Point, interpolatedTextBounds: Rect): Point {
when (horizontalAlignment) {
HorizontalAlignment.LEFT -> {
inPoint.x = lockScreenPaint.strokeWidth.toInt() - interpolatedTextBounds.left
@@ -422,7 +444,9 @@ open class SimpleDigitalClockTextView(
// translation of reference point of text
// used for translation when calling textInterpolator
private fun getLocalTranslation(): Point {
- val interpolatedTextBounds = updateInterpolatedTextBounds()
+ val interpolatedTextBounds = getInterpolatedTextBounds()
+ setInterpolatedViewBounds(interpolatedTextBounds)
+
val localTranslation = Point(0, 0)
val correctedBaseline = if (baseline != -1) baseline else baselineFromMeasure
// get the change from current baseline to expected baseline
@@ -452,7 +476,7 @@ open class SimpleDigitalClockTextView(
}
}
- return updateXtranslation(localTranslation, interpolatedTextBounds)
+ return updateXTranslation(localTranslation, interpolatedTextBounds)
}
fun applyStyles(textStyle: FontTextStyle, aodStyle: FontTextStyle?) {
@@ -463,7 +487,7 @@ open class SimpleDigitalClockTextView(
textStyle.lineHeight?.let { lineHeight = it.toInt() }
this.aodStyle = aodStyle ?: textStyle.copy()
- this.aodStyle.transitionInterpolator?.let { aodDozingInterpolator = it }
+ aodDozingInterpolator = this.aodStyle.transitionInterpolator ?: Interpolators.LINEAR
lockScreenPaint.strokeWidth = textBorderWidth
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
setInterpolatorPaint()
@@ -492,7 +516,7 @@ open class SimpleDigitalClockTextView(
recomputeMaxSingleDigitSizes()
if (this::textAnimator.isInitialized) {
- textAnimator.setTextStyle(textSize = lockScreenPaint.textSize, animate = false)
+ textAnimator.setTextStyle(TextAnimator.Style(textSize = lockScreenPaint.textSize))
}
}
@@ -517,10 +541,11 @@ open class SimpleDigitalClockTextView(
textAnimator.textInterpolator.targetPaint.set(lockScreenPaint)
textAnimator.textInterpolator.onTargetPaintModified()
textAnimator.setTextStyle(
- fvar = lsFontVariation,
- textSize = lockScreenPaint.textSize,
- color = lockscreenColor,
- animate = false,
+ TextAnimator.Style(
+ fVar = lsFontVariation,
+ textSize = lockScreenPaint.textSize,
+ color = lockscreenColor,
+ )
)
}
}
@@ -564,6 +589,17 @@ open class SimpleDigitalClockTextView(
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, 1.0f, 43)
.compose()
+ val CHARGE_ANIMATION_DURATION = 500L
+ val FIDGET_ANIMATION_DURATION = 250L
+ val FIDGET_INTERPOLATOR = PathInterpolator(0.26873f, 0f, 0.45042f, 1f)
+ val FIDGET_DISTS =
+ mapOf(
+ GSFAxes.WEIGHT to Pair(200f, 500f),
+ GSFAxes.WIDTH to Pair(30f, 75f),
+ GSFAxes.ROUND to Pair(0f, 50f),
+ GSFAxes.SLANT to Pair(0f, -5f),
+ )
+
val AOD_COLOR = Color.WHITE
val LS_WEIGHT_AXIS = ClockFontAxisSetting(GSFAxes.WEIGHT, 400f)
val AOD_WEIGHT_AXIS = ClockFontAxisSetting(GSFAxes.WEIGHT, 200f)
diff --git a/packages/SystemUI/docs/qs-tiles.md b/packages/SystemUI/docs/qs-tiles.md
index ee388ec8e5c5..87d9b7c3b853 100644
--- a/packages/SystemUI/docs/qs-tiles.md
+++ b/packages/SystemUI/docs/qs-tiles.md
@@ -8,6 +8,14 @@ This document is a more or less comprehensive summary of the state and infrastru
Settings tiles. It provides descriptions about the lifecycle of a tile, how to create new tiles and
how SystemUI manages and displays tiles, among other topics.
+A lot of the tile backend architecture is in the process of being replaced by a new architecture in
+order to align with the
+[recommended architecture](https://developer.android.com/topic/architecture#recommended-app-arch).
+
+While we are in the process of migrating, this document will try to provide a comprehensive
+overview of the current architecture as well as the new one. The sections documenting the new
+architecture are marked with the tag [NEW-ARCH].
+
## What are Quick Settings Tiles?
Quick Settings (from now on, QS) is the expanded panel that contains shortcuts for the user to
@@ -72,6 +80,27 @@ The interfaces in `QSTile` as well as other interfaces described in this documen
implement plugins to add additional tiles or different behavior. For more information,
see [plugins.md](plugins.md)
+
+#### [NEW-ARCH] Tile backend
+Instead of `QSTileImpl` the tile backend is made of a view model called `QSTileViewModelImpl`,
+which in turn is composed of 3 interfaces:
+
+* [`QSTileDataInteractor`](/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataInteractor.kt)
+is responsible for providing the data for the tile. It is responsible for fetching the state of
+the tile from the source of truth and providing that information to the tile. Typically the data
+interactor will read system state from a repository or a controller and provide a flow of
+domain-specific data model.
+
+* [`QSTileUserActionInteractor`](/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt) is responsible for handling the user actions on the tile.
+This interactor decides what should happen when the user clicks, long clicks on the tile.
+
+* [`QSTileDataToStateMapper`](/packages/SystemUI/src/com/android/systemui/qs/tiles/base/mapper/QSTileMapper.kt)
+is responsible for mapping the data received from the data interactor to a state that the view
+model can use to update the UI.
+
+At the time being, the `QSTileViewModel`s are adapted to `QSTile`. This conversion is done by
+`QSTileViewModelAdapter`.
+
#### Tile State
Each tile has an associated `State` object that is used to communicate information to the
@@ -94,6 +123,11 @@ Additionally. `BooleanState` has a `value` boolean field that usually would be s
to `state == Tile#STATE_ACTIVE`. This is used by accessibility services along
with `expandedAccessibilityClassName`.
+#### [NEW-ARCH] Tile State
+In the new architecture, the mapper generates
+[`QSTileState`](packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt),
+which again is converted to the old state by `QSTileViewModelAdapter`.
+
#### SystemUI tiles
Each tile defined in SystemUI extends `QSTileImpl`. This abstract class implements some common
@@ -103,6 +137,9 @@ to handle different events (refresh, click, etc.).
For more information on how to implement a tile in SystemUI,
see [Implementing a SystemUI tile](#implementing-a-systemui-tile).
+As mentioned before, when the [NEW-ARCH] migration is complete, we will remove the `QSTileImpl`
+and `QSTileViewModelAdapter` and directly use`QSTileViewModelImpl`.
+
### Tile views
Each Tile has a couple of associated views for displaying it in QS and QQS. These views are updated
@@ -154,37 +191,24 @@ corresponding `QSTile` with its `QSTileView`, doing the following:
#### Life of a tile click
This is a brief run-down of what happens when a user clicks on a tile. Internal changes on the
-device (for example, changes from Settings) will trigger this process starting in step 3. Throughout
-this section, we assume that we are dealing with a `QSTileImpl`.
-
-1. User clicks on tile. The following calls happen in sequence:
- 1. `QSTileViewImpl#onClickListener`.
- 2. `QSTile#click`.
- 3. `QSTileImpl#handleClick`. This last call sets the new state for the device by using the
- associated controller.
-2. State in the device changes. This is normally outside of SystemUI's control.
-3. Controller receives a callback (or `Intent`) indicating the change in the device. The following
- calls happen:
- 1. `QSTileImpl#refreshState`, maybe passing an object with necessary information regarding the
- new state.
- 2. `QSTileImpl#handleRefreshState`
-4. `QSTileImpl#handleUpdateState` is called to update the state with the new information. This
- information can be obtained both from the `Object` passed to `refreshState` as well as from the
- controller.
-5. If the state has changed (in at least one element), `QSTileImpl#handleStateChanged` is called.
- This will trigger a call to all the associated `QSTile.Callback#onStateChanged`, passing the
- new `State`.
-6. `QSTileView#onStateChanged` is called and this calls `QSTileView#handleStateChanged`. This method
- maps the state into the view:
- * The tile colors change to match the new state.
- * `QSIconView.setIcon` is called to apply the correct state to the icon and the correct icon to
- the view.
- * The tile labels change to match the new state.
+device (for example, changes from Settings) will trigger this process starting in step 5.
+
+Step | Legacy Tiles | [NEW-ARCH] Tiles
+-------|-------|---------
+1 | User clicks on tile. | Same as legacy tiles.
+2 | `QSTileViewImpl#onClickListener` | Same as legacy tiles.
+3 | `QSTile#click` | Same as legacy tiles.
+4| `QSTileImpl#handleClick` | `QSTileUserActionInteractor#handleInput`
+5| State in the device changes. This is normally outside of SystemUI's control. Controller receives a callback (or `Intent`) indicating the change in the device. | Same as legacy tiles.
+6 | `QSTile#refreshState`and `QSTileImpl#handleRefreshState` | `QSTileDataInteractor#tileData()`
+7| `QSTileImpl#handleUpdateState` is called to update the state with the new information. This information can be obtained both from the `Object` passed to `refreshState` as well as from the controller. | The data that was generated by the data interactor is read by the `QSTileViewModelImpl.state` flow which calls `QSTileMapper#map` on the data to generate a new `QSTileState`.
+8| If the state has changed (in at least one element `QSTileImpl#handleStateChanged` is called. This will trigger a call to all the associated `QSTile.Callback#onStateChanged`, passing the new `State`. | The newly mapped QSTileState is read by the `QSTileViewModelAdapter` which then maps it to a legacy `State`. Similarly to the legacy tiles, the new state is compared to the old one and if there is a difference, `QSTile.Callback#onStateChanged` is called for all the associated callbacks.
+9 | `QSTileView#onStateChanged` is called and this calls `QSTileView#handleStateChanged`. This method maps the state updating tile color and label, and calling `QSIconView.setIcon` | Same as legacy tiles.
## Third party tiles (TileService)
-A third party tile is any Quick Settings tile that is provided by an app (that's not SystemUI). This
-is implemented by developers
+A third party tile is any Quick Settings tile that is provided by an app (that's not SystemUI).
+This is implemented by developers
subclassing [`TileService`](/core/java/android/service/quicksettings/TileService.java) and
interacting with its API.
@@ -220,9 +244,9 @@ from SystemUI:
* **`onTileAdded`**: called when the tile is added to QS.
* **`onTileRemoved`**: called when the tile is removed from QS.
* **`onStartListening`**: called when QS is opened and the tile is showing. This marks the start of
- the window when calling `getQSTile` is safe and will provide the correct object.
-* **`onStopListening`**: called when QS is closed or the tile is no longer visible by the user. This
- marks the end of the window described in `onStartListening`.
+the window when calling `getQSTile` is safe and will provide the correct object.
+* **`onStopListening`**: called when QS is closed or the tile is no longer visible by the user.
+This marks the end of the window described in `onStartListening`.
* **`onClick`**: called when the user clicks on the tile.
Additionally, the following final methods are provided:
@@ -379,13 +403,14 @@ correct list of tiles.
### QSFactory
+`CurrentTilesInteractorImpl` uses the `QSFactory` interface to create the tiles.
+
This interface provides a way of creating tiles and views from a spec. It can be used in plugins to
provide different definitions for tiles.
-In SystemUI there is only one implementation of this factory and that is the default
-factory (`QSFactoryImpl`) in `CurrentTilesInteractorImpl`.
+In SystemUI there are two implementation of this factory. The first one is `QSFactoryImpl` in used for legacy tiles. The second one is `NewQSFactory` used for [NEW-ARCH] tiles.
-#### QSFactoryImpl
+#### QSFactoryImpl (legacy tiles)
This class implements the following method as specified in the `QSFactory` interface:
@@ -402,6 +427,12 @@ This class implements the following method as specified in the `QSFactory` inter
As part of filtering not valid tiles, custom tiles that don't have a corresponding valid service
component are never instantiated.
+#### NewQSFactory ([NEW-ARCH] tiles)
+
+This class also implements the `createTile` method as specified in the `QSFactory` interface.
+However, it first uses the spec to get a `QSTileViewModel`. The view model is then adapted into a
+`QSTile` using the `QSTileViewModelAdapter`.
+
### Lifecycle of a Tile
We describe first the parts of the lifecycle that are common to SystemUI tiles and third party
@@ -415,7 +446,7 @@ tiles.
2. This updates the flow that `CurrentTilesInteractor` is collecting from, triggering the process
described above.
3. `CurrentTilesInteractor` calls the available `QSFactory` classes in order to find one that will
- be able to create a tile with that spec. Assuming that `QSFactoryImpl` managed to create the
+ be able to create a tile with that spec. Assuming that some factory managed to create the
tile, which is some implementation of `QSTile` (either a SystemUI subclass
of `QSTileImpl` or a `CustomTile`) it will be added to the current list.
If the tile is available, it's stored in a map and things proceed forward.
@@ -452,7 +483,7 @@ in [Third party tiles (TileService)](#third-party-tiles-tileservice).
This section describes necessary and recommended steps when implementing a Quick Settings tile. Some
of them are optional and depend on the requirements of the tile.
-### Implementing a SystemUI tile
+### Implementing a legacy SystemUI tile
1. Create a class (preferably
in [`SystemUI/src/com/android/systemui/qs/tiles`](/packages/SystemUI/src/com/android/systemui/qs/tiles))
@@ -579,6 +610,70 @@ type variable of type `State`.
Provides a default label for this Tile. Used by the QS Panel customizer to show a name next to
each available tile.
+### Implementing a [NEW-ARCH] SystemUI tile
+In the new system the tiles are created in the path
+[`packages/SystemUI/src/com/android/systemui/qs/tiles/impl/<spec>`](packages/SystemUI/src/com/android/systemui/qs/tiles/impl/<spec>)
+where the `<spec>` should be replaced by the spec of the tile e.g. rotation for `RotationLockTile`.
+
+To create a new tile, the developer needs to implement the following data class and interfaces:
+
+[`DataModel`] is a class that describes the system state of the feature that the tile is trying to
+represent. Let's refer to the type of this class as DATA_TYPE. For example a simplified version of
+the data model for a flashlight tile could be a class with a boolean field that represents
+whether the flashlight is on or not.
+
+This file should be placed in the relative path `domain/model/` down from the tile's package.
+
+[`QSTileDataInteractor`] There are two abstract methods that need to be implemented:
+* `fun tileData(user: UserHandle, triggers: Flow<DataUpdateTrigger>): Flow<DATA_TYPE>`: This method
+returns a flow of data that will be used to create the state of the tile. This is where the system
+state is listened to and converted to a flow of data model. Avoid loading data or settings up
+listeners on the main thread. The userHandle is the user for which the tile is created.
+The triggers flow is a flow of events that can be used to trigger a refresh of the data.
+The most common triggers the force update and initial request.
+
+* `fun availability(user: UserHandle): Flow<Boolean>`: This method returns a flow of booleans that
+indicates if the tile should be shown or not. This is where the availability of the system feature
+(e.g. wifi) is checked. The userHandle is the user for which the tile is created.
+
+This file should be placed in the relative path `domain/interactor/` down from the tile's package.
+
+[`QSTileUserActionInteractor`]
+* `fun handleInput(input: QSTileInput)` is the method that needs to be implemented. This is the
+method that will be called when the user interacts with the tile. The input parameter contains
+the type of interaction (click, long click, toggle) and the DATA_TYPE of the latest data when the
+input was received.
+
+This file should be placed in the relative path `/domain/interactor` down from the tile's package.
+
+[`QSTileDataToStateMapper`]
+* `fun map(data: DATA_TYPE): QSTileState` is the method that needs to be implemented. This method
+is responsible for mapping the data received from the data interactor to a state that the view
+model can use to update the UI. This is where for example the icon should be loaded, and the
+label and content description set. The map function will run on UIBackground thread, a single
+thread which has higher priority than the background thread and lower than UI thread. Loading a
+resource on UI thread can cause jank by blocking the UI thread. On the other end of the spectrum,
+loading resources using a background dispatcher may cause jank due to background thread contention
+since it is possible for the background dispatcher to use more than one background thread
+at the same time. In contrast, the UIBackground dispatcher uses a single thread that is
+shared by all tiles. Therefore the system will use UIBackground dispatcher to execute
+the map function.
+
+The most important resource to load in the map function is the icon. We prefer `Icon.Loaded` with a
+resource id over `Icon.Resource`, because then (a) we can guarantee that the drawable loading will
+happen on the UIBackground thread and (b) we can cache the drawables using the resource id.
+
+This file should be placed in the relative path `/ui/mapper` down from the tile's package.
+
+#### Testing a [NEW-ARCH] SystemUI tile
+
+When writing tests, the mapper is usually a good place to start, since that is where the
+business logic decisions are being made that can inform the shape of data interactor.
+
+We suggest taking advantage of the existing class `QSTileStateSubject`. So rather than
+asserting an individual field's value, a test will assert the whole state. That can be
+achieved by `QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)`.
+
### Implementing a third party tile
For information about this, use the Android Developer documentation
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
index bd811814eb24..4140a956182c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -18,9 +18,7 @@ package com.android.keyguard;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -28,8 +26,6 @@ import static org.mockito.Mockito.when;
import android.hardware.biometrics.BiometricSourceType;
import android.testing.TestableLooper;
-import android.text.Editable;
-import android.text.TextWatcher;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -99,19 +95,6 @@ public class KeyguardMessageAreaControllerTest extends SysuiTestCase {
}
@Test
- public void textChanged_AnnounceForAccessibility() {
- ArgumentCaptor<TextWatcher> textWatcherArgumentCaptor = ArgumentCaptor.forClass(
- TextWatcher.class);
- mMessageAreaController.onViewAttached();
- verify(mKeyguardMessageArea).addTextChangedListener(textWatcherArgumentCaptor.capture());
-
- textWatcherArgumentCaptor.getValue().afterTextChanged(
- Editable.Factory.getInstance().newEditable("abc"));
- verify(mKeyguardMessageArea).removeCallbacks(any(Runnable.class));
- verify(mKeyguardMessageArea).postDelayed(any(Runnable.class), anyLong());
- }
-
- @Test
public void testSetBouncerVisible() {
mMessageAreaController.setIsVisible(true);
verify(mKeyguardMessageArea).setIsVisible(true);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryTest.kt
index d6ba98d65d15..441f807a8ec8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryTest.kt
@@ -31,6 +31,7 @@ import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.log.core.Logger
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.testKosmos
+import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -136,6 +137,118 @@ class ActivityManagerRepositoryTest : SysuiTestCase() {
assertThat(latest).isFalse()
}
+ @Test
+ fun createAppVisibilityFlow_fetchesInitialValue_trueWithLastVisibleTime() =
+ kosmos.runTest {
+ whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_FOREGROUND)
+ fakeSystemClock.setCurrentTimeMillis(5000)
+
+ val latest by
+ collectLastValue(underTest.createAppVisibilityFlow(THIS_UID, logger, LOG_TAG))
+
+ assertThat(latest!!.isAppCurrentlyVisible).isTrue()
+ assertThat(latest!!.lastAppVisibleTime).isEqualTo(5000)
+ }
+
+ @Test
+ fun createAppVisibilityFlow_fetchesInitialValue_falseWithoutLastVisibleTime() =
+ kosmos.runTest {
+ whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_GONE)
+ fakeSystemClock.setCurrentTimeMillis(5000)
+
+ val latest by
+ collectLastValue(underTest.createAppVisibilityFlow(THIS_UID, logger, LOG_TAG))
+
+ assertThat(latest!!.isAppCurrentlyVisible).isFalse()
+ assertThat(latest!!.lastAppVisibleTime).isNull()
+ }
+
+ @Test
+ fun createAppVisibilityFlow_getsImportanceUpdates_updatesLastVisibleTimeOnlyWhenVisible() =
+ kosmos.runTest {
+ whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_GONE)
+ fakeSystemClock.setCurrentTimeMillis(5000)
+ val latest by
+ collectLastValue(underTest.createAppVisibilityFlow(THIS_UID, logger, LOG_TAG))
+
+ assertThat(latest!!.isAppCurrentlyVisible).isFalse()
+ assertThat(latest!!.lastAppVisibleTime).isNull()
+
+ val listenerCaptor = argumentCaptor<ActivityManager.OnUidImportanceListener>()
+ verify(activityManager).addOnUidImportanceListener(listenerCaptor.capture(), any())
+ val listener = listenerCaptor.firstValue
+
+ // WHEN the app becomes visible
+ fakeSystemClock.setCurrentTimeMillis(7000)
+ listener.onUidImportance(THIS_UID, IMPORTANCE_FOREGROUND)
+
+ // THEN the status and lastAppVisibleTime are updated
+ assertThat(latest!!.isAppCurrentlyVisible).isTrue()
+ assertThat(latest!!.lastAppVisibleTime).isEqualTo(7000)
+
+ // WHEN the app is no longer visible
+ listener.onUidImportance(THIS_UID, IMPORTANCE_TOP_SLEEPING)
+
+ // THEN the lastAppVisibleTime is preserved
+ assertThat(latest!!.isAppCurrentlyVisible).isFalse()
+ assertThat(latest!!.lastAppVisibleTime).isEqualTo(7000)
+
+ // WHEN the app is visible again
+ fakeSystemClock.setCurrentTimeMillis(9000)
+ listener.onUidImportance(THIS_UID, IMPORTANCE_FOREGROUND)
+
+ // THEN the lastAppVisibleTime is updated
+ assertThat(latest!!.isAppCurrentlyVisible).isTrue()
+ assertThat(latest!!.lastAppVisibleTime).isEqualTo(9000)
+ }
+
+ @Test
+ fun createAppVisibilityFlow_ignoresUpdatesForOtherUids() =
+ kosmos.runTest {
+ val latest by
+ collectLastValue(underTest.createAppVisibilityFlow(THIS_UID, logger, LOG_TAG))
+
+ val listenerCaptor = argumentCaptor<ActivityManager.OnUidImportanceListener>()
+ verify(activityManager).addOnUidImportanceListener(listenerCaptor.capture(), any())
+ val listener = listenerCaptor.firstValue
+
+ listener.onUidImportance(THIS_UID, IMPORTANCE_GONE)
+ assertThat(latest!!.isAppCurrentlyVisible).isFalse()
+
+ // WHEN another UID becomes foreground
+ listener.onUidImportance(THIS_UID + 2, IMPORTANCE_FOREGROUND)
+
+ // THEN this UID still stays not visible
+ assertThat(latest!!.isAppCurrentlyVisible).isFalse()
+ }
+
+ @Test
+ fun createAppVisibilityFlow_securityExceptionOnUidRegistration_ok() =
+ kosmos.runTest {
+ whenever(activityManager.getUidImportance(THIS_UID)).thenReturn(IMPORTANCE_GONE)
+ whenever(activityManager.addOnUidImportanceListener(any(), any()))
+ .thenThrow(SecurityException())
+
+ val latest by
+ collectLastValue(underTest.createAppVisibilityFlow(THIS_UID, logger, LOG_TAG))
+
+ // Verify no crash, and we get a value emitted
+ assertThat(latest!!.isAppCurrentlyVisible).isFalse()
+ }
+
+ /** Regression test for b/216248574. */
+ @Test
+ fun createAppVisibilityFlow_getUidImportanceThrowsException_ok() =
+ kosmos.runTest {
+ whenever(activityManager.getUidImportance(any())).thenThrow(SecurityException())
+
+ val latest by
+ collectLastValue(underTest.createAppVisibilityFlow(THIS_UID, logger, LOG_TAG))
+
+ // Verify no crash, and we get a value emitted
+ assertThat(latest!!.isAppCurrentlyVisible).isFalse()
+ }
+
companion object {
private const val THIS_UID = 558
private const val LOG_TAG = "LogTag"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
index e492c63d095c..052d520ac92f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
@@ -17,16 +17,20 @@
package com.android.systemui.animation
import android.os.HandlerThread
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper
import android.view.View
import android.widget.FrameLayout
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.jank.InteractionJankMonitor
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.view.LaunchableFrameLayout
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertThrows
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -40,6 +44,14 @@ class GhostedViewTransitionAnimatorControllerTest : SysuiTestCase() {
}
private val interactionJankMonitor = FakeInteractionJankMonitor()
+ private lateinit var transitionRegistry: FakeViewTransitionRegistry
+ private lateinit var transitioningView: View
+
+ @Before
+ fun setup() {
+ transitioningView = LaunchableFrameLayout(mContext)
+ transitionRegistry = FakeViewTransitionRegistry()
+ }
@Test
fun animatingOrphanViewDoesNotCrash() {
@@ -67,7 +79,7 @@ class GhostedViewTransitionAnimatorControllerTest : SysuiTestCase() {
parent.addView((launchView))
val launchController =
GhostedViewTransitionAnimatorController(
- launchView,
+ launchView,
launchCujType = LAUNCH_CUJ,
returnCujType = RETURN_CUJ,
interactionJankMonitor = interactionJankMonitor
@@ -96,6 +108,26 @@ class GhostedViewTransitionAnimatorControllerTest : SysuiTestCase() {
assertThat(interactionJankMonitor.finished).containsExactly(LAUNCH_CUJ, RETURN_CUJ)
}
+ @EnableFlags(Flags.FLAG_DECOUPLE_VIEW_CONTROLLER_IN_ANIMLIB)
+ @Test
+ fun testViewsAreRegisteredInTransitionRegistry() {
+ GhostedViewTransitionAnimatorController(
+ transitioningView = transitioningView,
+ transitionRegistry = transitionRegistry
+ )
+ assertThat(transitionRegistry.registry).isNotEmpty()
+ }
+
+ @DisableFlags(Flags.FLAG_DECOUPLE_VIEW_CONTROLLER_IN_ANIMLIB)
+ @Test
+ fun testNotUseRegistryIfDecouplingFlagDisabled() {
+ GhostedViewTransitionAnimatorController(
+ transitioningView = transitioningView,
+ transitionRegistry = transitionRegistry
+ )
+ assertThat(transitionRegistry.registry).isEmpty()
+ }
+
/**
* A fake implementation of [InteractionJankMonitor] which stores ongoing and finished CUJs and
* allows inspection.
@@ -117,4 +149,30 @@ class GhostedViewTransitionAnimatorControllerTest : SysuiTestCase() {
return true
}
}
+
+ private class FakeViewTransitionRegistry : IViewTransitionRegistry {
+
+ val registry = mutableMapOf<ViewTransitionToken, View>()
+
+ override fun register(token: ViewTransitionToken, view: View) {
+ registry[token] = view
+ view.setTag(R.id.tag_view_transition_token, token)
+ }
+
+ override fun unregister(token: ViewTransitionToken) {
+ registry.remove(token)?.setTag(R.id.tag_view_transition_token, null)
+ }
+
+ override fun getView(token: ViewTransitionToken): View? {
+ return registry[token]
+ }
+
+ override fun getViewToken(view: View): ViewTransitionToken? {
+ return view.getTag(R.id.tag_view_transition_token) as? ViewTransitionToken
+ }
+
+ override fun onRegistryUpdate() {
+ //empty
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
index 4d238ac3798d..8c5fad3906ed 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.back.domain.interactor
-import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.DeviceFlagsValueProvider
@@ -32,7 +31,6 @@ import androidx.test.filters.SmallTest
import com.android.internal.statusbar.IStatusBarService
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.communal.domain.interactor.CommunalBackActionInteractor
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
@@ -93,7 +91,6 @@ class BackActionInteractorTest : SysuiTestCase() {
@Mock private lateinit var onBackInvokedDispatcher: WindowOnBackInvokedDispatcher
@Mock private lateinit var iStatusBarService: IStatusBarService
@Mock private lateinit var headsUpManager: HeadsUpManager
- @Mock private lateinit var communalBackActionInteractor: CommunalBackActionInteractor
private val keyguardRepository = FakeKeyguardRepository()
private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor by lazy {
@@ -118,7 +115,6 @@ class BackActionInteractorTest : SysuiTestCase() {
windowRootViewVisibilityInteractor,
shadeBackActionInteractor,
qsController,
- communalBackActionInteractor,
)
}
@@ -297,19 +293,6 @@ class BackActionInteractorTest : SysuiTestCase() {
verify(shadeBackActionInteractor).onBackProgressed(0.4f)
}
- @Test
- @EnableFlags(Flags.FLAG_GLANCEABLE_HUB_BACK_ACTION)
- fun onBackAction_communalCanBeDismissed_communalBackActionInteractorCalled() {
- backActionInteractor.start()
- windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
- powerInteractor.setAwakeForTest()
- val callback = getBackInvokedCallback()
- whenever(communalBackActionInteractor.canBeDismissed()).thenReturn(true)
- callback.onBackInvoked()
-
- verify(communalBackActionInteractor).onBackPressed()
- }
-
private fun getBackInvokedCallback(): OnBackInvokedCallback {
testScope.runCurrent()
val captor = argumentCaptor<OnBackInvokedCallback>()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
index 01baadda7c87..c40c1a3b0e93 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
@@ -130,12 +130,17 @@ public class SeekBarWithIconButtonsViewTest extends SysuiTestCase {
@Test
public void setProgress_onProgressChangedAndOnUserInteractionFinalized() {
reset(mOnSeekBarChangeListener);
- mIconDiscreteSliderLinearLayout.setProgress(1);
+
+ // Trigger the progress changed listener with fromUser but without clicking.
+ // This is similar to what would happen if an accessibility service changed the
+ // progress.
+ mIconDiscreteSliderLinearLayout.getSeekBarChangeListener().onProgressChanged(
+ mIconDiscreteSliderLinearLayout.getSeekbar(), 1, /*fromUser=*/ true);
// If users are changing seekbar progress without touching the seekbar or clicking the
// buttons, trigger onUserInteractionFinalized.
verify(mOnSeekBarChangeListener).onProgressChanged(
- eq(mSeekbar), /* progress= */ eq(1), /* fromUser= */ eq(false));
+ eq(mSeekbar), /* progress= */ eq(1), /* fromUser= */ eq(true));
verify(mOnSeekBarChangeListener, never()).onStartTrackingTouch(/* seekBar= */ any());
verify(mOnSeekBarChangeListener, never()).onStopTrackingTouch(/* seekBar= */ any());
verify(mOnSeekBarChangeListener).onUserInteractionFinalized(
@@ -144,6 +149,22 @@ public class SeekBarWithIconButtonsViewTest extends SysuiTestCase {
}
@Test
+ public void setProgress_onProgressChangedWithoutUserInteractionFinalized() {
+ reset(mOnSeekBarChangeListener);
+ mIconDiscreteSliderLinearLayout.setProgress(1);
+
+ // If seekbar progress changes due to a non-user event, without touching the seekbar or
+ // clicking the buttons, do not trigger onUserInteractionFinalized.
+ verify(mOnSeekBarChangeListener).onProgressChanged(
+ eq(mSeekbar), /* progress= */ eq(1), /* fromUser= */ eq(false));
+ verify(mOnSeekBarChangeListener, never()).onStartTrackingTouch(/* seekBar= */ any());
+ verify(mOnSeekBarChangeListener, never()).onStopTrackingTouch(/* seekBar= */ any());
+ verify(mOnSeekBarChangeListener, never()).onUserInteractionFinalized(
+ /* seekBar= */ any(),
+ eq(OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER));
+ }
+
+ @Test
public void setProgressToSeekBarByTouch_onUserInteractionFinalizedAfterTouchEnds() {
reset(mOnSeekBarChangeListener);
final SeekBarWithIconButtonsView.SeekBarChangeListener seekBarChangeListener =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index e9b88499a6f7..7051f81cfc88 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -24,45 +24,47 @@ import android.provider.Settings
import androidx.test.filters.SmallTest
import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
+import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.dock.dockManager
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.notificationShadeWindowController
-import com.android.systemui.statusbar.phone.centralSurfacesOptional
import com.android.systemui.testKosmos
import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
+import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.advanceTimeBy
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(ParameterizedAndroidJunit4::class)
@EnableFlags(FLAG_COMMUNAL_HUB)
@@ -74,7 +76,8 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
@JvmStatic
@Parameters(name = "{0}")
fun getParams(): List<FlagsParameterization> {
- return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ return FlagsParameterization.allCombinationsOf(FLAG_GLANCEABLE_HUB_V2)
+ .andSceneContainer()
}
}
@@ -82,9 +85,22 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
mSetFlagsRule.setFlagsParameterization(flags)
}
- private val kosmos = testKosmos()
-
- private lateinit var underTest: CommunalSceneStartable
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+
+ private val Kosmos.underTest by
+ Kosmos.Fixture {
+ CommunalSceneStartable(
+ communalInteractor = communalInteractor,
+ communalSettingsInteractor = communalSettingsInteractor,
+ communalSceneInteractor = communalSceneInteractor,
+ keyguardInteractor = keyguardInteractor,
+ systemSettings = fakeSettings,
+ notificationShadeWindowController = notificationShadeWindowController,
+ bgScope = applicationCoroutineScope,
+ mainDispatcher = testDispatcher,
+ uiEventLogger = uiEventLoggerFake,
+ )
+ }
@Before
fun setUp() {
@@ -94,352 +110,314 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
SCREEN_TIMEOUT,
UserHandle.USER_CURRENT,
)
- kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
-
- underTest =
- CommunalSceneStartable(
- dockManager = dockManager,
- communalInteractor = communalInteractor,
- communalSettingsInteractor = communalSettingsInteractor,
- communalSceneInteractor = communalSceneInteractor,
- keyguardTransitionInteractor = keyguardTransitionInteractor,
- keyguardInteractor = keyguardInteractor,
- systemSettings = fakeSettings,
- notificationShadeWindowController = notificationShadeWindowController,
- applicationScope = applicationCoroutineScope,
- bgScope = applicationCoroutineScope,
- mainDispatcher = testDispatcher,
- centralSurfacesOpt = centralSurfacesOptional,
- uiEventLogger = uiEventLoggerFake,
- )
- .apply { start() }
+ fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
+
+ underTest.start()
// Make communal available so that communalInteractor.desiredScene accurately reflects
// scene changes instead of just returning Blank.
- with(kosmos.testScope) {
- launch { setCommunalAvailable(true) }
- testScheduler.runCurrent()
- }
+ runBlocking { setCommunalAvailable(true) }
+ setCommunalV2ConfigEnabled(true)
}
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_whenDreaming_goesToBlank() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Scene times out back to blank after the screen timeout.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- }
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_notDreaming_staysOnCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is not dreaming and on communal.
- updateDreaming(false)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- // Scene stays as Communal
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
- }
+ kosmos.runTest {
+ // Device is not dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(false)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ // Scene stays as Communal
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_dreamStopped_staysOnCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Wait a bit, but not long enough to timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Dream stops, timeout is cancelled and device stays on hub, because the regular
- // screen timeout will take effect at this point.
- updateDreaming(false)
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
- }
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Dream stops, timeout is cancelled and device stays on hub, because the regular
+ // screen timeout will take effect at this point.
+ fakeKeyguardRepository.setDreaming(false)
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_dreamStartedHalfway_goesToCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is on communal, but not dreaming.
- updateDreaming(false)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Wait a bit, but not long enough to timeout, then start dreaming.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- updateDreaming(true)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Device times out after one screen timeout interval, dream doesn't reset timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- }
+ kosmos.runTest {
+ // Device is on communal, but not dreaming.
+ fakeKeyguardRepository.setDreaming(false)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Wait a bit, but not long enough to timeout, then start dreaming.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ fakeKeyguardRepository.setDreaming(true)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Device times out after one screen timeout interval, dream doesn't reset timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_dreamAfterInitialTimeout_goesToBlank() =
- with(kosmos) {
- testScope.runTest {
- // Device is on communal.
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- // Device stays on the hub after the timeout since we're not dreaming.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Start dreaming.
- updateDreaming(true)
- advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
-
- // Hub times out immediately.
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- }
+ kosmos.runTest {
+ // Device is on communal.
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ // Device stays on the hub after the timeout since we're not dreaming.
+ testScope.advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Start dreaming.
+ fakeKeyguardRepository.setDreaming(true)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS.milliseconds)
+
+ // Hub times out immediately.
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_userActivityTriggered_resetsTimeout() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
- // Wait a bit, but not long enough to timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- // Send user interaction to reset timeout.
- communalInteractor.signalUserInteraction()
+ // Send user interaction to reset timeout.
+ communalInteractor.signalUserInteraction()
- // If user activity didn't reset timeout, we would have gone back to Blank by now.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
+ // If user activity didn't reset timeout, we would have gone back to Blank by now.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
- // Timeout happens one interval after the user interaction.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- }
+ // Timeout happens one interval after the user interaction.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_screenTimeoutChanged() =
- with(kosmos) {
- testScope.runTest {
- fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
-
- // Device is dreaming and on communal.
- updateDreaming(true)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Scene times out back to blank after the screen timeout.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- assertThat(uiEventLoggerFake.logs.first().eventId)
- .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
- assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
- }
+ kosmos.runTest {
+ fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
+
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
+ assertThat(uiEventLoggerFake.logs.first().eventId)
+ .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_whenDreaming_goesToBlank() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Scene times out back to blank after the screen timeout.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(Scenes.Dream)
- }
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_notDreaming_staysOnCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is not dreaming and on communal.
- updateDreaming(false)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- // Scene stays as Communal
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
- }
+ kosmos.runTest {
+ // Device is not dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(false)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ // Scene stays as Communal
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_dreamStopped_staysOnCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Wait a bit, but not long enough to timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Dream stops, timeout is cancelled and device stays on hub, because the regular
- // screen timeout will take effect at this point.
- updateDreaming(false)
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Communal)
- }
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Dream stops, timeout is cancelled and device stays on hub, because the regular
+ // screen timeout will take effect at this point.
+ fakeKeyguardRepository.setDreaming(false)
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_dreamStartedHalfway_goesToCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is on communal, but not dreaming.
- updateDreaming(false)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Wait a bit, but not long enough to timeout, then start dreaming.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- updateDreaming(true)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Device times out after one screen timeout interval, dream doesn't reset timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Dream)
- }
+ kosmos.runTest {
+ // Device is on communal, but not dreaming.
+ fakeKeyguardRepository.setDreaming(false)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Wait a bit, but not long enough to timeout, then start dreaming.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ fakeKeyguardRepository.setDreaming(true)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Device times out after one screen timeout interval, dream doesn't reset timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_dreamAfterInitialTimeout_goesToBlank() =
- with(kosmos) {
- testScope.runTest {
- // Device is on communal.
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- // Device stays on the hub after the timeout since we're not dreaming.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Start dreaming.
- updateDreaming(true)
- advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
-
- // Hub times out immediately.
- assertThat(scene).isEqualTo(Scenes.Dream)
- }
+ kosmos.runTest {
+ // Device is on communal.
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ // Device stays on the hub after the timeout since we're not dreaming.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Start dreaming.
+ fakeKeyguardRepository.setDreaming(true)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS.milliseconds)
+
+ // Hub times out immediately.
+ assertThat(scene).isEqualTo(Scenes.Dream)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_userActivityTriggered_resetsTimeout() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- sceneInteractor.changeScene(Scenes.Communal, "test")
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
- // Wait a bit, but not long enough to timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- // Send user interaction to reset timeout.
- communalInteractor.signalUserInteraction()
+ // Send user interaction to reset timeout.
+ communalInteractor.signalUserInteraction()
- // If user activity didn't reset timeout, we would have gone back to Blank by now.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Communal)
+ // If user activity didn't reset timeout, we would have gone back to Blank by now.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
- // Timeout happens one interval after the user interaction.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Dream)
- }
+ // Timeout happens one interval after the user interaction.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_screenTimeoutChanged() =
- with(kosmos) {
- testScope.runTest {
- fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
-
- // Device is dreaming and on communal.
- updateDreaming(true)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Scene times out back to blank after the screen timeout.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(Scenes.Dream)
- assertThat(uiEventLoggerFake.logs.first().eventId)
- .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
- assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
- }
- }
+ kosmos.runTest {
+ fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
- private fun TestScope.updateDreaming(dreaming: Boolean) =
- with(kosmos) {
- fakeKeyguardRepository.setDreaming(dreaming)
- runCurrent()
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
+ assertThat(uiEventLoggerFake.logs.first().eventId)
+ .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
}
+
+ /**
+ * Advances time by duration + 1 millisecond, to ensure that tasks scheduled to run at
+ * currentTime + duration are scheduled.
+ */
+ private fun Kosmos.advanceTimeBy(duration: Duration) =
+ testScope.advanceTimeBy(duration + 1.milliseconds)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorTest.kt
deleted file mode 100644
index 70f38f7bc94e..000000000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorTest.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.communal.domain.interactor
-
-import android.platform.test.annotations.EnableFlags
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.communal.data.repository.communalSceneRepository
-import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.kosmos.runCurrent
-import com.android.systemui.kosmos.runTest
-import com.android.systemui.testKosmos
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class CommunalBackActionInteractorTest : SysuiTestCase() {
- private val kosmos = testKosmos()
-
- private var Kosmos.underTest by Fixture { communalBackActionInteractor }
-
- @Test
- @EnableFlags(FLAG_COMMUNAL_HUB)
- fun communalShowing_canBeDismissed() =
- kosmos.runTest {
- setCommunalAvailable(true)
- assertThat(underTest.canBeDismissed()).isEqualTo(false)
- communalInteractor.changeScene(CommunalScenes.Communal, "test")
- runCurrent()
- assertThat(underTest.canBeDismissed()).isEqualTo(true)
- }
-
- @Test
- @EnableFlags(FLAG_COMMUNAL_HUB)
- fun onBackPressed_invokesSceneChange() =
- kosmos.runTest {
- underTest.onBackPressed()
- runCurrent()
- assertThat(communalSceneRepository.currentScene.value).isEqualTo(CommunalScenes.Blank)
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
index feee9e3d62d2..6eace1b50ea7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
@@ -128,6 +128,19 @@ class CommunalTutorialInteractorTest : SysuiTestCase() {
}
@Test
+ fun tutorialState_startedAndCommunalSceneShowing_stateWillNotUpdate() =
+ testScope.runTest {
+ val tutorialSettingState by
+ collectLastValue(communalTutorialRepository.tutorialSettingState)
+
+ communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)
+
+ goToCommunal()
+
+ assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_STARTED)
+ }
+
+ @Test
fun tutorialState_completedAndCommunalSceneShowing_stateWillNotUpdate() =
testScope.runTest {
val tutorialSettingState by
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
index ff5fa3959c6d..7374f181760c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
@@ -37,7 +37,6 @@ import com.android.systemui.testKosmos
import com.android.systemui.touchpad.data.repository.FakeTouchpadRepository
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.hours
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -51,7 +50,6 @@ import org.mockito.Mockito.times
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
-import org.mockito.kotlin.firstValue
import org.mockito.kotlin.never
import org.mockito.kotlin.secondValue
import org.mockito.kotlin.verify
@@ -116,7 +114,6 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() {
fun showTouchpadNotification() = runTestAndClear {
touchpadRepository.setIsAnyTouchpadConnected(true)
testScope.advanceTimeBy(LAUNCH_DELAY)
- mockExistingNotification()
verifyNotification(
R.string.launch_touchpad_tutorial_notification_title,
R.string.launch_touchpad_tutorial_notification_content,
@@ -142,14 +139,10 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() {
}
@Test
- fun showKeyboardNotificationThenDisconnectKeyboard() = runTestAndClear {
+ fun cancelKeyboardNotificationWhenKeyboardDisconnects() = runTestAndClear {
keyboardRepository.setIsAnyKeyboardConnected(true)
testScope.advanceTimeBy(LAUNCH_DELAY)
- verifyNotification(
- R.string.launch_keyboard_tutorial_notification_title,
- R.string.launch_keyboard_tutorial_notification_content,
- )
- mockExistingNotification()
+ mockNotifications(hasTutorialNotification = true)
// After the keyboard is disconnected, i.e. there is nothing connected, the notification
// should be cancelled
@@ -158,22 +151,71 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() {
}
@Test
- fun showKeyboardTouchpadNotificationThenDisconnectKeyboard() = runTestAndClear {
+ fun updateNotificationToTouchpadOnlyWhenKeyboardDisconnects() = runTestAndClear {
keyboardRepository.setIsAnyKeyboardConnected(true)
touchpadRepository.setIsAnyTouchpadConnected(true)
testScope.advanceTimeBy(LAUNCH_DELAY)
- mockExistingNotification()
+ mockNotifications(hasTutorialNotification = true)
+
keyboardRepository.setIsAnyKeyboardConnected(false)
verify(notificationManager, times(2))
.notifyAsUser(eq(TAG), eq(NOTIFICATION_ID), notificationCaptor.capture(), any())
- // Connect both device and the first notification is for both
- notificationCaptor.firstValue.verify(
+ // Connect both device and the first notification is for both. After the keyboard is
+ // disconnected, i.e. with only the touchpad left, the notification should be update to
+ // touchpad only
+ notificationCaptor.secondValue.verify(
+ R.string.launch_touchpad_tutorial_notification_title,
+ R.string.launch_touchpad_tutorial_notification_content,
+ )
+ }
+
+ @Test
+ fun updateNotificationToBothDevicesWhenTouchpadConnects() = runTestAndClear {
+ keyboardRepository.setIsAnyKeyboardConnected(true)
+ testScope.advanceTimeBy(LAUNCH_DELAY)
+ mockNotifications(hasTutorialNotification = true)
+
+ touchpadRepository.setIsAnyTouchpadConnected(true)
+
+ verify(notificationManager, times(2))
+ .notifyAsUser(eq(TAG), eq(NOTIFICATION_ID), notificationCaptor.capture(), any())
+ // Update the notification from keyboard to both devices
+ notificationCaptor.secondValue.verify(
R.string.launch_keyboard_touchpad_tutorial_notification_title,
R.string.launch_keyboard_touchpad_tutorial_notification_content,
)
- // After the keyboard is disconnected, i.e. with only the touchpad left, the notification
- // should be update to the one for only touchpad
+ }
+
+ @Test
+ fun doNotShowUpdateNotificationWhenInitialNotificationIsDismissed() = runTestAndClear {
+ keyboardRepository.setIsAnyKeyboardConnected(true)
+ testScope.advanceTimeBy(LAUNCH_DELAY)
+ mockNotifications(hasTutorialNotification = false)
+
+ touchpadRepository.setIsAnyTouchpadConnected(true)
+
+ // There's only one notification being shown throughout this scenario. We don't update the
+ // notification because it has been dismissed when the touchpad connects
+ verifyNotification(
+ R.string.launch_keyboard_tutorial_notification_title,
+ R.string.launch_keyboard_tutorial_notification_content,
+ )
+ }
+
+ @Test
+ fun showTouchpadNotificationAfterDelayAndKeyboardNotificationIsDismissed() = runTestAndClear {
+ keyboardRepository.setIsAnyKeyboardConnected(true)
+ testScope.advanceTimeBy(LAUNCH_DELAY)
+ mockNotifications(hasTutorialNotification = false)
+
+ touchpadRepository.setIsAnyTouchpadConnected(true)
+ testScope.advanceTimeBy(LAUNCH_DELAY)
+
+ verify(notificationManager, times(2))
+ .notifyAsUser(eq(TAG), eq(NOTIFICATION_ID), notificationCaptor.capture(), any())
+ // The keyboard notification was shown and dismissed; the touchpad notification is scheduled
+ // independently
notificationCaptor.secondValue.verify(
R.string.launch_touchpad_tutorial_notification_title,
R.string.launch_touchpad_tutorial_notification_content,
@@ -189,10 +231,12 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() {
}
}
- // Assume that there's an existing notification when the updater checks activeNotifications
- private fun mockExistingNotification() {
+ // Mock an active notification, so when the updater checks activeNotifications, it returns one
+ // with the given id. Otherwise, return an empty array (i.e. no active notifications)
+ private fun mockNotifications(hasTutorialNotification: Boolean) {
whenever(notification.id).thenReturn(NOTIFICATION_ID)
- whenever(notificationManager.activeNotifications).thenReturn(arrayOf(notification))
+ val notifications = if (hasTutorialNotification) arrayOf(notification) else emptyArray()
+ whenever(notificationManager.activeNotifications).thenReturn(notifications)
}
private fun verifyNotification(@StringRes titleResId: Int, @StringRes contentResId: Int) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
index 183e4d6f624b..98486a22854a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -541,7 +541,7 @@ object TestShortcuts {
simpleShortcutCategory(System, "System apps", "Take a note"),
simpleShortcutCategory(System, "System controls", "Take screenshot"),
simpleShortcutCategory(System, "System controls", "Go back"),
- simpleShortcutCategory(MultiTasking, "Split screen", "Switch to full screen"),
+ simpleShortcutCategory(MultiTasking, "Split screen", "Use full screen"),
simpleShortcutCategory(
MultiTasking,
"Split screen",
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
index 2feabf8221ad..63229dbb47a4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
@@ -34,23 +34,32 @@ package com.android.systemui.keyguard.domain.interactor
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.Flags
+import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.testKosmos
+import com.google.common.truth.Truth
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -58,10 +67,25 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.reset
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class FromAlternateBouncerTransitionInteractorTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class FromAlternateBouncerTransitionInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf(FLAG_GLANCEABLE_HUB_V2)
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags)
+ }
+
private val kosmos =
testKosmos().apply {
this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
@@ -74,6 +98,7 @@ class FromAlternateBouncerTransitionInteractorTest : SysuiTestCase() {
fun setup() {
transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
underTest = kosmos.fromAlternateBouncerTransitionInteractor
+ kosmos.setCommunalV2ConfigEnabled(true)
underTest.start()
}
@@ -171,6 +196,72 @@ class FromAlternateBouncerTransitionInteractorTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun transitionToOccluded_glanceableHubShowing() =
+ kosmos.runTest {
+ val currentScene by collectLastValue(communalSceneInteractor.currentScene)
+
+ fakePowerRepository.updateWakefulness(
+ WakefulnessState.AWAKE,
+ WakeSleepReason.POWER_BUTTON,
+ WakeSleepReason.POWER_BUTTON,
+ false,
+ )
+ fakeKeyguardRepository.setKeyguardOccluded(false)
+ fakeKeyguardBouncerRepository.setAlternateVisible(true)
+ fakeCommunalSceneRepository.changeScene(CommunalScenes.Communal)
+ runCurrent()
+
+ Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
+
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ testScope,
+ )
+ reset(transitionRepository)
+
+ fakeKeyguardRepository.setKeyguardOccluded(true)
+ fakeKeyguardBouncerRepository.setAlternateVisible(false)
+ testScope.advanceTimeBy(200) // advance past delay
+
+ Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+ }
+
+ @Test
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun transitionToDreaming() =
+ kosmos.runTest {
+ fakePowerRepository.updateWakefulness(
+ WakefulnessState.AWAKE,
+ WakeSleepReason.POWER_BUTTON,
+ WakeSleepReason.POWER_BUTTON,
+ false,
+ )
+ fakeKeyguardRepository.setKeyguardOccluded(false)
+ fakeKeyguardBouncerRepository.setAlternateVisible(true)
+ runCurrent()
+
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ testScope,
+ )
+ reset(transitionRepository)
+
+ fakeKeyguardRepository.setKeyguardOccluded(true)
+ fakeKeyguardRepository.setDreaming(true)
+ fakeKeyguardBouncerRepository.setAlternateVisible(false)
+ testScope.advanceTimeBy(200) // advance past delay
+
+ assertThat(transitionRepository)
+ .startedTransition(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.DREAMING,
+ )
+ }
+
+ @Test
@DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun transitionToGone_whenOpeningGlanceableHubEditMode() =
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
index 63bb1001c873..d9e76222e51f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
@@ -17,13 +17,17 @@
package com.android.systemui.keyguard.domain.interactor
import android.platform.test.annotations.EnableFlags
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalV2Available
+import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy
@@ -33,30 +37,55 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
+import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.testKosmos
-import com.android.systemui.user.domain.interactor.selectedUserInteractor
+import com.google.common.truth.Truth
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.reset
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class FromPrimaryBouncerTransitionInteractorTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class FromPrimaryBouncerTransitionInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf(FLAG_GLANCEABLE_HUB_V2)
+ }
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags)
+ }
+
private val kosmos =
testKosmos().apply {
this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy
}
val underTest = kosmos.fromPrimaryBouncerTransitionInteractor
val testScope = kosmos.testScope
- val selectedUserInteractor = kosmos.selectedUserInteractor
val transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
val bouncerRepository = kosmos.fakeKeyguardBouncerRepository
+ @Before
+ fun setUp() {
+ kosmos.setCommunalV2ConfigEnabled(true)
+ }
+
@Test
fun testSurfaceBehindVisibility() =
testScope.runTest {
@@ -213,4 +242,33 @@ class FromPrimaryBouncerTransitionInteractorTest : SysuiTestCase() {
to = KeyguardState.OCCLUDED,
)
}
+
+ @Test
+ @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+ fun testTransitionToDozing_bouncerShowingOnTopOfGlanceableHub() =
+ kosmos.runTest {
+ underTest.start()
+ setCommunalV2Available(true)
+
+ val currentScene by collectLastValue(communalSceneInteractor.currentScene)
+ // Communal is showing.
+ fakeCommunalSceneRepository.changeScene(CommunalScenes.Communal)
+
+ Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
+
+ // Bouncer is shown on top of the Glanceable Hub.
+ bouncerRepository.setPrimaryShow(true)
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ testScope,
+ )
+
+ reset(transitionRepository)
+
+ powerInteractor.setAsleepForTest()
+ runCurrent()
+
+ Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt
index 282bebcd629a..a08c0dea6fa6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt
@@ -30,6 +30,7 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepos
import com.android.systemui.keyguard.data.repository.keyguardClockRepository
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.keyguard.shared.model.ClockSize
+import com.android.systemui.keyguard.shared.model.ClockSizeSetting
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -68,6 +69,7 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
fun clockSize_sceneContainerFlagOff_basedOnRepository() =
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
+ kosmos.fakeKeyguardClockRepository.setSelectedClockSize(ClockSizeSetting.DYNAMIC)
kosmos.keyguardClockRepository.setClockSize(ClockSize.LARGE)
assertThat(value).isEqualTo(ClockSize.LARGE)
@@ -76,6 +78,17 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
}
@Test
+ @DisableSceneContainer
+ fun clockSize_sceneContainerFlagOff_smallClockSettingSelected_SMALL() =
+ testScope.runTest {
+ val value by collectLastValue(underTest.clockSize)
+ kosmos.fakeKeyguardClockRepository.setSelectedClockSize(ClockSizeSetting.SMALL)
+ kosmos.keyguardClockRepository.setClockSize(ClockSize.LARGE)
+
+ assertThat(value).isEqualTo(ClockSize.SMALL)
+ }
+
+ @Test
@EnableSceneContainer
fun clockSize_forceSmallClock_SMALL() =
testScope.runTest {
@@ -91,61 +104,80 @@ class KeyguardClockInteractorTest : SysuiTestCase() {
@Test
@EnableSceneContainer
- fun clockSize_SceneContainerFlagOn_shadeModeSingle_hasNotifs_SMALL() =
+ fun clockSize_sceneContainerFlagOn_shadeModeSingle_hasNotifs_SMALL() =
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
kosmos.shadeRepository.setShadeLayoutWide(false)
kosmos.activeNotificationListRepository.setActiveNotifs(1)
+
assertThat(value).isEqualTo(ClockSize.SMALL)
}
@Test
@EnableSceneContainer
- fun clockSize_SceneContainerFlagOn_shadeModeSingle_hasMedia_SMALL() =
+ fun clockSize_sceneContainerFlagOn_shadeModeSingle_hasMedia_SMALL() =
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
kosmos.shadeRepository.setShadeLayoutWide(false)
val userMedia = MediaData().copy(active = true)
kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
+
assertThat(value).isEqualTo(ClockSize.SMALL)
}
@Test
@EnableSceneContainer
- fun clockSize_SceneContainerFlagOn_shadeModeSplit_isMediaVisible_SMALL() =
+ fun clockSize_sceneContainerFlagOn_shadeModeSplit_isMediaVisible_SMALL() =
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
val userMedia = MediaData().copy(active = true)
kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
kosmos.keyguardRepository.setIsDozing(false)
+
assertThat(value).isEqualTo(ClockSize.SMALL)
}
@Test
@EnableSceneContainer
- fun clockSize_SceneContainerFlagOn_shadeModeSplit_noMedia_LARGE() =
+ fun clockSize_sceneContainerFlagOn_shadeModeSplit_noMedia_LARGE() =
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.keyguardRepository.setIsDozing(false)
+
assertThat(value).isEqualTo(ClockSize.LARGE)
}
@Test
@EnableSceneContainer
- fun clockSize_SceneContainerFlagOn_shadeModeSplit_isDozing_LARGE() =
+ fun clockSize_sceneContainerFlagOn_shadeModeSplit_isDozing_LARGE() =
testScope.runTest {
val value by collectLastValue(underTest.clockSize)
val userMedia = MediaData().copy(active = true)
kosmos.shadeRepository.setShadeLayoutWide(true)
kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
kosmos.keyguardRepository.setIsDozing(true)
+
assertThat(value).isEqualTo(ClockSize.LARGE)
}
@Test
@EnableSceneContainer
+ fun clockSize_sceneContainerFlagOn_shadeModeSplit_smallClockSettingSelectd_SMALL() =
+ testScope.runTest {
+ val value by collectLastValue(underTest.clockSize)
+ val userMedia = MediaData().copy(active = true)
+ kosmos.fakeKeyguardClockRepository.setSelectedClockSize(ClockSizeSetting.SMALL)
+ kosmos.shadeRepository.setShadeLayoutWide(true)
+ kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
+ kosmos.keyguardRepository.setIsDozing(true)
+
+ assertThat(value).isEqualTo(ClockSize.SMALL)
+ }
+
+ @Test
+ @EnableSceneContainer
fun clockShouldBeCentered_sceneContainerFlagOn_notSplitMode_true() =
testScope.runTest {
val value by collectLastValue(underTest.clockShouldBeCentered)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index fee2dfc88020..0b42898d82ae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -23,6 +23,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -51,6 +52,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -58,11 +60,18 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class KeyguardTransitionInteractorTest : SysuiTestCase() {
- val kosmos = testKosmos()
- val testScope = kosmos.testScope
- val repository = kosmos.fakeKeyguardTransitionRepository
- val underTest by lazy { kosmos.keyguardTransitionInteractor }
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var underTest: KeyguardTransitionInteractor
+
+ @Before
+ fun setup() {
+ repository = kosmos.fakeKeyguardTransitionRepository
+ underTest = kosmos.keyguardTransitionInteractor
+ }
@Test
fun transitionCollectorsReceivesOnlyAppropriateEvents() =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index a090faba5bf7..8df70ef0fd2e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.app.StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
@@ -30,7 +31,6 @@ import com.android.systemui.Flags.glanceableHubV2
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.communal.domain.interactor.CommunalSceneTransitionInteractor
-import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSceneTransitionInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
@@ -126,14 +126,14 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
}
private val powerInteractor by lazy { kosmos.powerInteractor }
- private val communalInteractor by lazy { kosmos.communalInteractor }
private val communalSceneInteractor by lazy { kosmos.communalSceneInteractor }
companion object {
@JvmStatic
@Parameters(name = "{0}")
fun getParams(): List<FlagsParameterization> {
- return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ return FlagsParameterization.allCombinationsOf(FLAG_GLANCEABLE_HUB_V2)
+ .andSceneContainer()
}
}
@@ -902,6 +902,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest
@Test
@DisableSceneContainer
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun primaryBouncerToGlanceableHubWhileDreaming() =
testScope.runTest {
// Setup - Move past initial delay with [KeyguardInteractor#isAbleToDream]
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt
index 26fe379f00bf..3cff0fc96af4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt
@@ -1358,6 +1358,45 @@ class LockscreenSceneTransitionInteractorTest : SysuiTestCase() {
)
}
+ /**
+ * When a transition away from the lockscreen is interrupted by an `Idle(Lockscreen)`, a
+ * `sceneState` that was set during the transition is consumed and passed to KTF.
+ */
+ @Test
+ fun transition_from_ls_scene_sceneStateSet_then_interrupted_by_idle_on_ls() =
+ testScope.runTest {
+ val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions)
+ sceneTransitions.value =
+ ObservableTransitionState.Transition(
+ Scenes.Lockscreen,
+ Scenes.Gone,
+ flowOf(Scenes.Lockscreen),
+ progress,
+ false,
+ flowOf(false),
+ )
+ progress.value = 0.4f
+ assertTransition(
+ step = currentStep!!,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.UNDEFINED,
+ state = TransitionState.RUNNING,
+ progress = 0.4f,
+ )
+
+ val sceneState = KeyguardState.AOD
+ underTest.onSceneAboutToChange(toScene = Scenes.Lockscreen, sceneState = sceneState)
+ sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+
+ assertTransition(
+ step = currentStep!!,
+ from = KeyguardState.UNDEFINED,
+ to = KeyguardState.AOD,
+ state = TransitionState.FINISHED,
+ progress = 1f,
+ )
+ }
+
private fun assertTransition(
step: TransitionStep,
from: KeyguardState? = null,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
index 3a016ff7152a..63770803ff48 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
@@ -40,7 +40,6 @@ import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusBarSec
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultUdfpsAccessibilityOverlaySection
import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSliceViewSection
import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
-import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
import com.android.systemui.util.mockito.whenever
import java.util.Optional
import org.junit.Before
@@ -66,7 +65,6 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() {
@Mock private lateinit var defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection
@Mock private lateinit var defaultStatusBarViewSection: DefaultStatusBarSection
@Mock private lateinit var defaultNSSLSection: DefaultNotificationStackScrollLayoutSection
- @Mock private lateinit var splitShadeGuidelines: SplitShadeGuidelines
@Mock private lateinit var aodPromotedNotificationSection: AodPromotedNotificationSection
@Mock private lateinit var aodNotificationIconsSection: AodNotificationIconsSection
@Mock private lateinit var aodBurnInSection: AodBurnInSection
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
index 8a599a1bd948..20d015f4d77c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
@@ -27,7 +27,6 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.keyguardClockRepository
import com.android.systemui.keyguard.shared.model.ClockSize
-import com.android.systemui.keyguard.shared.model.ClockSizeSetting
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel.ClockLayout
import com.android.systemui.kosmos.testScope
@@ -55,17 +54,18 @@ import platform.test.runner.parameterized.Parameters
@SmallTest
@RunWith(ParameterizedAndroidJunit4::class)
class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
- val kosmos = testKosmos()
- val testScope = kosmos.testScope
- val underTest by lazy { kosmos.keyguardClockViewModel }
- val res = context.resources
- @Mock lateinit var clockController: ClockController
- @Mock lateinit var largeClock: ClockFaceController
- @Mock lateinit var smallClock: ClockFaceController
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val underTest by lazy { kosmos.keyguardClockViewModel }
+ private val res = context.resources
- var config = ClockConfig("TEST", "Test", "")
- var faceConfig = ClockFaceConfig()
+ @Mock private lateinit var clockController: ClockController
+ @Mock private lateinit var largeClock: ClockFaceController
+ @Mock private lateinit var smallClock: ClockFaceController
+
+ private var config = ClockConfig("TEST", "Test", "")
+ private var faceConfig = ClockFaceConfig()
init {
mSetFlagsRule.setFlagsParameterization(flags)
@@ -196,35 +196,6 @@ class KeyguardClockViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
}
@Test
- fun testClockSize_alwaysSmallClockSize() =
- testScope.runTest {
- val value by collectLastValue(underTest.clockSize)
-
- with(kosmos) {
- fakeKeyguardClockRepository.setSelectedClockSize(ClockSizeSetting.SMALL)
- keyguardClockRepository.setClockSize(ClockSize.LARGE)
- }
-
- assertThat(value).isEqualTo(ClockSize.SMALL)
- }
-
- @Test
- @DisableSceneContainer
- fun testClockSize_dynamicClockSize() =
- testScope.runTest {
- with(kosmos) {
- val value by collectLastValue(underTest.clockSize)
- fakeKeyguardClockRepository.setSelectedClockSize(ClockSizeSetting.DYNAMIC)
-
- keyguardClockRepository.setClockSize(ClockSize.SMALL)
- assertThat(value).isEqualTo(ClockSize.SMALL)
-
- keyguardClockRepository.setClockSize(ClockSize.LARGE)
- assertThat(value).isEqualTo(ClockSize.LARGE)
- }
- }
-
- @Test
fun isLargeClockVisible_whenLargeClockSize_isTrue() =
testScope.runTest {
val value by collectLastValue(underTest.isLargeClockVisible)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelTest.kt
index 38829da69c28..583fd1e03002 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -81,4 +82,20 @@ class KeyguardMediaViewModelTest : SysuiTestCase() {
assertThat(underTest.isMediaVisible).isFalse()
}
+
+ @Test
+ fun isShadeLayoutWide_withConfigTrue_true() =
+ kosmos.runTest {
+ shadeRepository.setShadeLayoutWide(true)
+
+ assertThat(underTest.isShadeLayoutWide).isTrue()
+ }
+
+ @Test
+ fun isShadeLayoutWide_withConfigFalse_false() =
+ kosmos.runTest {
+ shadeRepository.setShadeLayoutWide(false)
+
+ assertThat(underTest.isShadeLayoutWide).isFalse()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
index af025273458f..0b34a01a0fe0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
@@ -17,19 +17,24 @@
package com.android.systemui.keyguard.ui.viewmodel
import android.platform.test.flag.junit.FlagsParameterization
+import androidx.compose.ui.Alignment
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.authController
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.transition.fakeKeyguardTransitionAnimationCallback
import com.android.systemui.keyguard.shared.transition.keyguardTransitionAnimationCallbackDelegator
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel.NotificationsPlacement.BelowClock
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel.NotificationsPlacement.BesideClock
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runCurrent
@@ -41,6 +46,10 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.enableDualShade
+import com.android.systemui.shade.domain.interactor.enableSingleShade
+import com.android.systemui.shade.domain.interactor.enableSplitShade
+import com.android.systemui.shade.domain.interactor.shadeModeInteractor
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.testKosmos
import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.whenever
@@ -99,136 +108,143 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
}
@Test
- @DisableSceneContainer
- fun clockSize_withLargeClock_true() =
+ fun notificationsPlacement_splitShade_topEnd() =
kosmos.runTest {
- val clockSize by collectLastValue(underTest.clockSize)
- fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
- assertThat(clockSize).isEqualTo(ClockSize.LARGE)
+ setupState(shadeMode = ShadeMode.Split, clockSize = ClockSize.SMALL)
+
+ assertThat(underTest.notificationsPlacement)
+ .isEqualTo(BesideClock(alignment = Alignment.TopEnd))
}
@Test
- @DisableSceneContainer
- fun clockSize_withSmallClock_false() =
+ fun notificationsPlacement_singleShade_below() =
kosmos.runTest {
- val clockSize by collectLastValue(underTest.clockSize)
- fakeKeyguardClockRepository.setClockSize(ClockSize.SMALL)
- assertThat(clockSize).isEqualTo(ClockSize.SMALL)
+ setupState(shadeMode = ShadeMode.Single, clockSize = ClockSize.SMALL)
+
+ assertThat(underTest.notificationsPlacement).isEqualTo(BelowClock)
}
@Test
- fun areNotificationsVisible_splitShadeTrue_true() =
+ @EnableSceneContainer
+ fun notificationsPlacement_dualShadeSmallClock_below() =
kosmos.runTest {
- val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
- shadeRepository.setShadeLayoutWide(true)
- fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
+ setupState(
+ shadeMode = ShadeMode.Dual,
+ clockSize = ClockSize.SMALL,
+ shadeLayoutWide = true,
+ )
- assertThat(areNotificationsVisible).isTrue()
+ assertThat(underTest.notificationsPlacement).isEqualTo(BelowClock)
}
@Test
- fun areNotificationsVisible_dualShadeWideOnLockscreen_true() =
+ @EnableSceneContainer
+ fun notificationsPlacement_dualShadeLargeClock_topStart() =
kosmos.runTest {
- val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
- kosmos.enableDualShade()
- shadeRepository.setShadeLayoutWide(true)
- fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
+ setupState(
+ shadeMode = ShadeMode.Dual,
+ clockSize = ClockSize.LARGE,
+ shadeLayoutWide = true,
+ )
- assertThat(areNotificationsVisible).isTrue()
+ assertThat(underTest.notificationsPlacement)
+ .isEqualTo(BesideClock(alignment = Alignment.TopStart))
}
@Test
- @DisableSceneContainer
- fun areNotificationsVisible_withSmallClock_true() =
+ fun areNotificationsVisible_splitShadeTrue_true() =
kosmos.runTest {
- val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
- fakeKeyguardClockRepository.setClockSize(ClockSize.SMALL)
- assertThat(areNotificationsVisible).isTrue()
+ setupState(shadeMode = ShadeMode.Split, clockSize = ClockSize.LARGE)
+
+ assertThat(underTest.areNotificationsVisible).isTrue()
}
@Test
- @DisableSceneContainer
- fun areNotificationsVisible_withLargeClock_false() =
+ @EnableSceneContainer
+ fun areNotificationsVisible_dualShadeWideOnLockscreen_true() =
kosmos.runTest {
- val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
- fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
- assertThat(areNotificationsVisible).isFalse()
+ setupState(
+ shadeMode = ShadeMode.Dual,
+ clockSize = ClockSize.LARGE,
+ shadeLayoutWide = true,
+ )
+
+ assertThat(underTest.areNotificationsVisible).isTrue()
}
@Test
- fun isShadeLayoutWide_withConfigTrue_true() =
+ @DisableSceneContainer
+ fun areNotificationsVisible_withSmallClock_true() =
kosmos.runTest {
- val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
- shadeRepository.setShadeLayoutWide(true)
+ setupState(shadeMode = ShadeMode.Single, clockSize = ClockSize.SMALL)
- assertThat(isShadeLayoutWide).isTrue()
+ assertThat(underTest.areNotificationsVisible).isTrue()
}
@Test
- fun isShadeLayoutWide_withConfigFalse_false() =
+ @DisableSceneContainer
+ fun areNotificationsVisible_withLargeClock_false() =
kosmos.runTest {
- val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
- shadeRepository.setShadeLayoutWide(false)
+ setupState(shadeMode = ShadeMode.Single, clockSize = ClockSize.LARGE)
- assertThat(isShadeLayoutWide).isFalse()
+ assertThat(underTest.areNotificationsVisible).isFalse()
}
@Test
fun unfoldTranslations() =
kosmos.runTest {
val maxTranslation = prepareConfiguration()
- val translations by collectLastValue(underTest.unfoldTranslations)
val unfoldProvider = fakeUnfoldTransitionProgressProvider
unfoldProvider.onTransitionStarted()
- assertThat(translations?.start).isEqualTo(0f)
- assertThat(translations?.end).isEqualTo(-0f)
+ runCurrent()
+ assertThat(underTest.unfoldTranslations.start).isZero()
+ assertThat(underTest.unfoldTranslations.end).isZero()
repeat(10) { repetition ->
val transitionProgress = 0.1f * (repetition + 1)
unfoldProvider.onTransitionProgress(transitionProgress)
- assertThat(translations?.start).isEqualTo((1 - transitionProgress) * maxTranslation)
- assertThat(translations?.end).isEqualTo(-(1 - transitionProgress) * maxTranslation)
+ runCurrent()
+ assertThat(underTest.unfoldTranslations.start)
+ .isEqualTo((1 - transitionProgress) * maxTranslation)
+ assertThat(underTest.unfoldTranslations.end)
+ .isEqualTo(-(1 - transitionProgress) * maxTranslation)
}
unfoldProvider.onTransitionFinishing()
- assertThat(translations?.start).isEqualTo(0f)
- assertThat(translations?.end).isEqualTo(-0f)
+ runCurrent()
+ assertThat(underTest.unfoldTranslations.start).isZero()
+ assertThat(underTest.unfoldTranslations.end).isZero()
unfoldProvider.onTransitionFinished()
- assertThat(translations?.start).isEqualTo(0f)
- assertThat(translations?.end).isEqualTo(-0f)
+ runCurrent()
+ assertThat(underTest.unfoldTranslations.start).isZero()
+ assertThat(underTest.unfoldTranslations.end).isZero()
}
@Test
fun isContentVisible_whenNotOccluded_visible() =
kosmos.runTest {
- val isContentVisible by collectLastValue(underTest.isContentVisible)
-
keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, null)
runCurrent()
- assertThat(isContentVisible).isTrue()
+ assertThat(underTest.isContentVisible).isTrue()
}
@Test
fun isContentVisible_whenOccluded_notVisible() =
kosmos.runTest {
- val isContentVisible by collectLastValue(underTest.isContentVisible)
-
keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, null)
fakeKeyguardTransitionRepository.transitionTo(
KeyguardState.LOCKSCREEN,
KeyguardState.OCCLUDED,
)
runCurrent()
- assertThat(isContentVisible).isFalse()
+ assertThat(underTest.isContentVisible).isFalse()
}
@Test
fun isContentVisible_whenOccluded_notVisible_evenIfShadeShown() =
kosmos.runTest {
- val isContentVisible by collectLastValue(underTest.isContentVisible)
-
keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, null)
fakeKeyguardTransitionRepository.transitionTo(
KeyguardState.LOCKSCREEN,
@@ -238,7 +254,7 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
sceneInteractor.snapToScene(Scenes.Shade, "")
runCurrent()
- assertThat(isContentVisible).isFalse()
+ assertThat(underTest.isContentVisible).isFalse()
}
@Test
@@ -260,17 +276,16 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
@Test
fun isContentVisible_whenOccluded_notVisibleInOccluded_visibleInAod() =
kosmos.runTest {
- val isContentVisible by collectLastValue(underTest.isContentVisible)
keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, null)
fakeKeyguardTransitionRepository.transitionTo(
- KeyguardState.LOCKSCREEN,
- KeyguardState.OCCLUDED,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
)
runCurrent()
sceneInteractor.snapToScene(Scenes.Shade, "")
runCurrent()
- assertThat(isContentVisible).isFalse()
+ assertThat(underTest.isContentVisible).isFalse()
fakeKeyguardTransitionRepository.transitionTo(KeyguardState.OCCLUDED, KeyguardState.AOD)
runCurrent()
@@ -278,9 +293,32 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
sceneInteractor.snapToScene(Scenes.Lockscreen, "")
runCurrent()
- assertThat(isContentVisible).isTrue()
+ assertThat(underTest.isContentVisible).isTrue()
}
+ private fun Kosmos.setupState(
+ shadeMode: ShadeMode,
+ clockSize: ClockSize,
+ shadeLayoutWide: Boolean? = null,
+ ) {
+ val isShadeLayoutWide by collectLastValue(kosmos.shadeRepository.isShadeLayoutWide)
+ val collectedClockSize by collectLastValue(kosmos.keyguardClockInteractor.clockSize)
+ val collectedShadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode)
+ when (shadeMode) {
+ ShadeMode.Dual -> kosmos.enableDualShade(wideLayout = shadeLayoutWide)
+ ShadeMode.Single -> kosmos.enableSingleShade()
+ ShadeMode.Split -> kosmos.enableSplitShade()
+ }
+ fakeKeyguardClockRepository.setShouldForceSmallClock(clockSize == ClockSize.SMALL)
+ fakeKeyguardClockRepository.setClockSize(clockSize)
+ runCurrent()
+ if (shadeLayoutWide != null) {
+ assertThat(isShadeLayoutWide).isEqualTo(shadeLayoutWide)
+ }
+ assertThat(collectedShadeMode).isEqualTo(shadeMode)
+ assertThat(collectedClockSize).isEqualTo(clockSize)
+ }
+
private fun prepareConfiguration(): Int {
val configuration = context.resources.configuration
configuration.setLayoutDirection(Locale.US)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java
index 95d9c8f4e819..a7a0c24e2163 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java
@@ -33,8 +33,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.WallpaperColors;
-import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
@@ -68,7 +66,7 @@ import java.util.stream.Collectors;
@SmallTest
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class MediaOutputAdapterTest extends SysuiTestCase {
+public class MediaOutputAdapterLegacyTest extends SysuiTestCase {
private static final String TEST_DEVICE_NAME_1 = "test_device_name_1";
private static final String TEST_DEVICE_NAME_2 = "test_device_name_2";
@@ -92,8 +90,8 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Captor
private ArgumentCaptor<SeekBar.OnSeekBarChangeListener> mOnSeekBarChangeListenerCaptor;
- private MediaOutputAdapter mMediaOutputAdapter;
- private MediaOutputAdapter.MediaDeviceViewHolder mViewHolder;
+ private MediaOutputAdapterLegacy mMediaOutputAdapter;
+ private MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy mViewHolder;
private List<MediaDevice> mMediaDevices = new ArrayList<>();
private List<MediaItem> mMediaItems = new ArrayList<>();
MediaOutputSeekbar mSpyMediaOutputSeekbar;
@@ -124,9 +122,9 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice1, true));
mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice2, false));
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mSpyMediaOutputSeekbar = spy(mViewHolder.mSeekBar);
}
@@ -150,9 +148,9 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Test
public void onBindViewHolder_bindPairNew_verifyView() {
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaItems.add(MediaItem.createPairNewDeviceMediaItem());
mMediaItems.add(MediaItem.createPairNewDeviceMediaItem());
@@ -175,9 +173,9 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
.map((item) -> item.getMediaDevice().get())
.collect(Collectors.toList()));
when(mMediaSwitchingController.getSessionName()).thenReturn(TEST_SESSION_NAME);
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.getItemCount();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -197,9 +195,9 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
.map((item) -> item.getMediaDevice().get())
.collect(Collectors.toList()));
when(mMediaSwitchingController.getSessionName()).thenReturn(null);
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.getItemCount();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -225,7 +223,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Test
public void onBindViewHolder_bindNonRemoteConnectedDevice_verifyView() {
when(mMediaSwitchingController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(false);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -240,10 +238,12 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@DisableFlags(Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING)
@Test
public void onBindViewHolder_bindConnectedRemoteDevice_verifyView() {
+ when(mMediaSwitchingController.getSelectedMediaDevice())
+ .thenReturn(ImmutableList.of(mMediaDevice1));
when(mMediaSwitchingController.getSelectableMediaDevice())
.thenReturn(ImmutableList.of(mMediaDevice2));
when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -262,7 +262,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaSwitchingController.getSelectableMediaDevice())
.thenReturn(ImmutableList.of(mMediaDevice2));
when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -274,7 +274,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
public void onBindViewHolder_bindSingleConnectedRemoteDevice_verifyView() {
when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(ImmutableList.of());
when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -292,7 +292,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaDevice1.hasOngoingSession()).thenReturn(true);
when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(ImmutableList.of());
when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -313,7 +313,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaDevice1.isHostForOngoingSession()).thenReturn(true);
when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(ImmutableList.of());
when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -346,7 +346,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaDevice1.isMutingExpectedDevice()).thenReturn(true);
when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(false);
when(mMediaSwitchingController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(false);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -496,7 +496,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaDevice1.getSubtextString()).thenReturn(TEST_CUSTOM_SUBTEXT);
when(mMediaDevice1.hasOngoingSession()).thenReturn(true);
when(mMediaDevice1.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_GO_TO_APP);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -520,7 +520,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaDevice2.getSubtext()).thenReturn(SUBTEXT_SUBSCRIPTION_REQUIRED);
when(mMediaDevice2.getSubtextString()).thenReturn(deviceStatus);
when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_GO_TO_APP);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
@@ -543,7 +543,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaDevice2.getSubtext()).thenReturn(SUBTEXT_AD_ROUTING_DISALLOWED);
when(mMediaDevice2.getSubtextString()).thenReturn(deviceStatus);
when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_NONE);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
@@ -565,7 +565,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaDevice1.getSubtextString()).thenReturn(TEST_CUSTOM_SUBTEXT);
when(mMediaDevice1.hasOngoingSession()).thenReturn(true);
when(mMediaDevice1.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_GO_TO_APP);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -625,9 +625,9 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Test
public void onItemClick_clickPairNew_verifyLaunchBluetoothPairing() {
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaItems.add(MediaItem.createPairNewDeviceMediaItem());
mMediaOutputAdapter.updateItems();
@@ -643,9 +643,9 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
assertThat(mMediaDevice2.getState()).isEqualTo(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_TRANSFER);
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.getItemCount();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -661,11 +661,12 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
assertThat(mMediaDevice2.getState()).isEqualTo(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_TRANSFER);
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
- MediaOutputAdapter.MediaDeviceViewHolder spyMediaDeviceViewHolder = spy(mViewHolder);
+ MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy spyMediaDeviceViewHolder = spy(
+ mViewHolder);
mMediaOutputAdapter.getItemCount();
mMediaOutputAdapter.onBindViewHolder(spyMediaDeviceViewHolder, 0);
@@ -682,11 +683,12 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaDevice2.getState()).thenReturn(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_GO_TO_APP);
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mMediaOutputAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
- MediaOutputAdapter.MediaDeviceViewHolder spyMediaDeviceViewHolder = spy(mViewHolder);
+ MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy spyMediaDeviceViewHolder = spy(
+ mViewHolder);
mMediaOutputAdapter.onBindViewHolder(spyMediaDeviceViewHolder, 1);
spyMediaDeviceViewHolder.mContainerLayout.performClick();
@@ -713,7 +715,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
List<MediaDevice> selectableDevices = new ArrayList<>();
selectableDevices.add(mMediaDevice2);
when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(selectableDevices);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
@@ -854,8 +856,10 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
.thenReturn(ImmutableList.of(mMediaDevice2));
when(mMediaSwitchingController.getDeselectableMediaDevice())
.thenReturn(ImmutableList.of(mMediaDevice1));
+ when(mMediaSwitchingController.getSelectedMediaDevice())
+ .thenReturn(ImmutableList.of(mMediaDevice1));
when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -895,16 +899,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
}
@Test
- public void updateColorScheme_triggerController() {
- WallpaperColors wallpaperColors = WallpaperColors.fromBitmap(
- Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888));
-
- mMediaOutputAdapter.updateColorScheme(wallpaperColors, true);
-
- verify(mMediaSwitchingController).setCurrentColorScheme(wallpaperColors, true);
- }
-
- @Test
public void updateItems_controllerItemsUpdated_notUpdatesInAdapterUntilUpdateItems() {
mMediaOutputAdapter.updateItems();
List<MediaItem> updatedList = new ArrayList<>();
@@ -986,7 +980,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
public void multipleSelectedDevices_verifySessionView() {
initializeSession();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(
new LinearLayout(mContext), MediaItem.MediaItemType.TYPE_DEVICE);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -1007,7 +1001,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
public void multipleSelectedDevices_verifyCollapsedView() {
initializeSession();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(
new LinearLayout(mContext), MediaItem.MediaItemType.TYPE_DEVICE);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
@@ -1020,13 +1014,13 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Test
public void multipleSelectedDevices_expandIconClicked_verifyInitialView() {
initializeSession();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(
new LinearLayout(mContext), MediaItem.MediaItemType.TYPE_DEVICE);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
mViewHolder.mEndTouchArea.performClick();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(
new LinearLayout(mContext), MediaItem.MediaItemType.TYPE_DEVICE);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -1043,13 +1037,13 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Test
public void multipleSelectedDevices_expandIconClicked_verifyCollapsedView() {
initializeSession();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(
new LinearLayout(mContext), MediaItem.MediaItemType.TYPE_DEVICE);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
mViewHolder.mEndTouchArea.performClick();
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(
new LinearLayout(mContext), MediaItem.MediaItemType.TYPE_DEVICE);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
@@ -1071,7 +1065,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaSwitchingController.getSelectedMediaDevice()).thenReturn(selectedDevices);
when(mMediaSwitchingController.getDeselectableMediaDevice()).thenReturn(new ArrayList<>());
- mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
+ mViewHolder = (MediaOutputAdapterLegacy.MediaDeviceViewHolderLegacy) mMediaOutputAdapter
.onCreateViewHolder(
new LinearLayout(mContext), MediaItem.MediaItemType.TYPE_DEVICE);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt
index 0bba8bba2419..b23cd5e5547f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.notifications.ui.viewmodel
+import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -28,6 +29,8 @@ import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
@@ -39,10 +42,13 @@ import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.enableDualShade
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayContentViewModel
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.update
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -50,6 +56,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@@ -155,6 +162,36 @@ class NotificationsShadeOverlayContentViewModelTest : SysuiTestCase() {
assertThat(underTest.showClock).isFalse()
}
+ @Test
+ fun showMedia_activeMedia_true() =
+ testScope.runTest {
+ kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true))
+ runCurrent()
+
+ assertThat(underTest.showMedia).isTrue()
+ }
+
+ @Test
+ fun showMedia_noActiveMedia_false() =
+ testScope.runTest {
+ kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = false))
+ runCurrent()
+
+ assertThat(underTest.showMedia).isFalse()
+ }
+
+ @Test
+ fun showMedia_qsDisabled_false() =
+ testScope.runTest {
+ kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true))
+ kosmos.fakeDisableFlagsRepository.disableFlags.update {
+ it.copy(disable2 = DISABLE2_QUICK_SETTINGS)
+ }
+ runCurrent()
+
+ assertThat(underTest.showMedia).isFalse()
+ }
+
private fun TestScope.lockDevice() {
val currentScene by collectLastValue(sceneInteractor.currentScene)
kosmos.powerInteractor.setAsleepForTest()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
index 64e6f4bd48b8..7ed3cb3e4586 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
@@ -34,7 +34,6 @@ import com.android.systemui.qs.flags.QSComposeFragment
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel
import com.android.systemui.qs.tiles.dialog.InternetDialogManager
-import com.android.systemui.qs.tiles.dialog.WifiStateWorker
import com.android.systemui.res.R
import com.android.systemui.statusbar.connectivity.AccessPointController
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
@@ -61,9 +60,6 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
-import org.mockito.kotlin.eq
-import org.mockito.kotlin.times
-import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
@@ -99,7 +95,6 @@ class InternetTileNewImplTest(flags: FlagsParameterization) : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var logger: QSLogger
@Mock private lateinit var dialogManager: InternetDialogManager
- @Mock private lateinit var wifiStateWorker: WifiStateWorker
@Mock private lateinit var accessPointController: AccessPointController
@Mock private lateinit var internetDetailsViewModelFactory: InternetDetailsViewModel.Factory
@@ -136,7 +131,6 @@ class InternetTileNewImplTest(flags: FlagsParameterization) : SysuiTestCase() {
logger,
viewModel,
dialogManager,
- wifiStateWorker,
accessPointController,
internetDetailsViewModelFactory,
)
@@ -245,26 +239,6 @@ class InternetTileNewImplTest(flags: FlagsParameterization) : SysuiTestCase() {
assertThat(underTest.state.secondaryLabel).isEqualTo(WIFI_SSID)
}
- @Test
- fun secondaryClick_turnsWifiOff() {
- whenever(wifiStateWorker.isWifiEnabled).thenReturn(true)
-
- underTest.secondaryClick(null)
- looper.processAllMessages()
-
- verify(wifiStateWorker, times(1)).isWifiEnabled = eq(false)
- }
-
- @Test
- fun secondaryClick_turnsWifiOn() {
- whenever(wifiStateWorker.isWifiEnabled).thenReturn(false)
-
- underTest.secondaryClick(null)
- looper.processAllMessages()
-
- verify(wifiStateWorker, times(1)).isWifiEnabled = eq(true)
- }
-
companion object {
const val WIFI_SSID = "test ssid"
val ACTIVE_WIFI =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 3a3f5371d195..61d0c8dbb087 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -345,11 +345,21 @@ public class ScreenRecordTileTest extends SysuiTestCase {
public void testNotStartingAndRecording_returnDetailsViewModel() {
when(mController.isStarting()).thenReturn(false);
when(mController.isRecording()).thenReturn(false);
+ when(mController.isScreenCaptureDisabled()).thenReturn(false);
mTile.getDetailsViewModel(Assert::assertNotNull);
}
@Test
@EnableFlags(QsDetailedView.FLAG_NAME)
+ public void testRecordingDisabled_notReturnDetailsViewModel() {
+ when(mController.isStarting()).thenReturn(false);
+ when(mController.isRecording()).thenReturn(false);
+ when(mController.isScreenCaptureDisabled()).thenReturn(true);
+ mTile.getDetailsViewModel(Assert::assertNull);
+ }
+
+ @Test
+ @EnableFlags(QsDetailedView.FLAG_NAME)
public void testStarting_notReturnDetailsViewModel() {
when(mController.isStarting()).thenReturn(true);
when(mController.isRecording()).thenReturn(false);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt
index b087bbc29bf7..54a653df696f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt
@@ -191,11 +191,7 @@ class InternetTileMapperTest : SysuiTestCase() {
label,
activationState,
secondaryLabel,
- setOf(
- QSTileState.UserAction.CLICK,
- QSTileState.UserAction.TOGGLE_CLICK,
- QSTileState.UserAction.LONG_CLICK,
- ),
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
contentDescription,
null,
QSTileState.SideViewIcon.Chevron,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt
index ce4a3432a5b4..3db5efcb6eb8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt
@@ -29,7 +29,6 @@ import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
import com.android.systemui.qs.tiles.dialog.InternetDetailsContentManager
import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel
import com.android.systemui.qs.tiles.dialog.InternetDialogManager
-import com.android.systemui.qs.tiles.dialog.WifiStateWorker
import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel
import com.android.systemui.statusbar.connectivity.AccessPointController
import com.android.systemui.util.mockito.nullable
@@ -56,7 +55,6 @@ class InternetTileUserActionInteractorTest : SysuiTestCase() {
private lateinit var underTest: InternetTileUserActionInteractor
private lateinit var internetDialogManager: InternetDialogManager
- private lateinit var wifiStateWorker: WifiStateWorker
private lateinit var controller: AccessPointController
private lateinit var internetDetailsViewModelFactory: InternetDetailsViewModel.Factory
private lateinit var internetDetailsContentManagerFactory: InternetDetailsContentManager.Factory
@@ -65,7 +63,6 @@ class InternetTileUserActionInteractorTest : SysuiTestCase() {
@Before
fun setup() {
internetDialogManager = mock<InternetDialogManager>()
- wifiStateWorker = mock<WifiStateWorker>()
controller = mock<AccessPointController>()
internetDetailsViewModelFactory = mock<InternetDetailsViewModel.Factory>()
internetDetailsContentManagerFactory = mock<InternetDetailsContentManager.Factory>()
@@ -81,7 +78,6 @@ class InternetTileUserActionInteractorTest : SysuiTestCase() {
InternetTileUserActionInteractor(
kosmos.testScope.coroutineContext,
internetDialogManager,
- wifiStateWorker,
controller,
inputHandler,
internetDetailsViewModelFactory,
@@ -133,26 +129,6 @@ class InternetTileUserActionInteractorTest : SysuiTestCase() {
}
@Test
- fun handleSecondaryClickWhenWifiOn() =
- kosmos.testScope.runTest {
- whenever(wifiStateWorker.isWifiEnabled).thenReturn(true)
-
- underTest.handleInput(QSTileInputTestKtx.toggleClick(InternetTileModel.Active()))
-
- verify(wifiStateWorker, times(1)).isWifiEnabled = eq(false)
- }
-
- @Test
- fun handleSecondaryClickWhenWifiOff() =
- kosmos.testScope.runTest {
- whenever(wifiStateWorker.isWifiEnabled).thenReturn(false)
-
- underTest.handleInput(QSTileInputTestKtx.toggleClick(InternetTileModel.Inactive()))
-
- verify(wifiStateWorker, times(1)).isWifiEnabled = eq(true)
- }
-
- @Test
fun detailsViewModel() =
kosmos.testScope.runTest {
assertThat(underTest.detailsViewModel.getTitle()).isEqualTo("Internet")
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 80c7026b0cea..23a0f6224fb7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -757,4 +757,46 @@ class SceneInteractorTest : SysuiTestCase() {
verify(processor, never()).onSceneAboutToChange(any(), any())
}
+
+ @Test
+ fun changeScene_sameScene_withFreeze() =
+ kosmos.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ val processor = mock<SceneInteractor.OnSceneAboutToChangeListener>()
+ underTest.registerSceneStateProcessor(processor)
+ verify(processor, never()).onSceneAboutToChange(any(), any())
+ assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(0)
+
+ underTest.changeScene(
+ toScene = Scenes.Lockscreen,
+ loggingReason = "test",
+ sceneState = KeyguardState.AOD,
+ forceSettleToTargetScene = true,
+ )
+
+ verify(processor).onSceneAboutToChange(Scenes.Lockscreen, KeyguardState.AOD)
+ assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(1)
+ }
+
+ @Test
+ fun changeScene_sameScene_withoutFreeze() =
+ kosmos.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ val processor = mock<SceneInteractor.OnSceneAboutToChangeListener>()
+ underTest.registerSceneStateProcessor(processor)
+ verify(processor, never()).onSceneAboutToChange(any(), any())
+ assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(0)
+
+ underTest.changeScene(
+ toScene = Scenes.Lockscreen,
+ loggingReason = "test",
+ sceneState = KeyguardState.AOD,
+ forceSettleToTargetScene = false,
+ )
+
+ verify(processor, never()).onSceneAboutToChange(any(), any())
+ assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(0)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
index 93ba8e1317fa..064fd485dab4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
@@ -28,6 +28,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.Log;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -52,6 +53,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
@SmallTest
+@FlakyTest(bugId = 395832204)
@RunWith(AndroidJUnit4.class)
public class PluginInstanceTest extends SysuiTestCase {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
index d92781a5f3ce..ef03fab95778 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
@@ -16,10 +16,8 @@
package com.android.systemui.shared.system
-import android.platform.test.annotations.DisableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BACK_ACTION
import com.android.systemui.SysuiTestCase
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING
@@ -32,7 +30,6 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class QuickStepContractTest : SysuiTestCase() {
@Test
- @DisableFlags(FLAG_GLANCEABLE_HUB_BACK_ACTION)
fun isBackGestureDisabled_hubShowing() {
val sysuiStateFlags = SYSUI_STATE_COMMUNAL_HUB_SHOWING
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index d2ea62da0940..83361dad9ff0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -76,7 +76,6 @@ import org.mockito.junit.MockitoJUnit
class NotificationShadeDepthControllerTest : SysuiTestCase() {
private val kosmos = testKosmos()
- private val applicationScope = kosmos.testScope.backgroundScope
@Mock private lateinit var windowRootViewBlurInteractor: WindowRootViewBlurInteractor
@Mock private lateinit var statusBarStateController: StatusBarStateController
@Mock private lateinit var blurUtils: BlurUtils
@@ -134,7 +133,6 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
context,
ResourcesSplitShadeStateController(),
windowRootViewBlurInteractor,
- applicationScope,
appZoomOutOptional,
dumpManager,
configurationController,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
index 05f2585cfaa5..5d1950670777 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
@@ -31,6 +31,7 @@ import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.testKosmos
+import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -183,7 +184,7 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() {
statusBarChipIcon = null,
promotedContent = PROMOTED_CONTENT,
),
- 32L,
+ creationTime = 32L,
)
val latest by collectLastValue(underTest.notificationChip)
@@ -246,7 +247,7 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() {
statusBarChipIcon = mock(),
promotedContent = PROMOTED_CONTENT,
)
- val underTest = factory.create(startingNotif, 123L)
+ val underTest = factory.create(startingNotif, creationTime = 123L)
val latest by collectLastValue(underTest.notificationChip)
assertThat(latest).isNotNull()
@@ -306,9 +307,10 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() {
}
@Test
- fun notificationChip_appIsVisibleOnCreation_emitsNull() =
+ fun notificationChip_appIsVisibleOnCreation_emitsIsAppVisibleTrueWithTime() =
kosmos.runTest {
activityManagerRepository.fake.startingIsAppVisibleValue = true
+ fakeSystemClock.setCurrentTimeMillis(9000)
val underTest =
factory.create(
@@ -323,13 +325,16 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() {
val latest by collectLastValue(underTest.notificationChip)
- assertThat(latest).isNull()
+ assertThat(latest).isNotNull()
+ assertThat(latest!!.isAppVisible).isTrue()
+ assertThat(latest!!.lastAppVisibleTime).isEqualTo(9000)
}
@Test
- fun notificationChip_appNotVisibleOnCreation_emitsValue() =
+ fun notificationChip_appNotVisibleOnCreation_emitsIsAppVisibleFalseWithNoTime() =
kosmos.runTest {
activityManagerRepository.fake.startingIsAppVisibleValue = false
+ fakeSystemClock.setCurrentTimeMillis(9000)
val underTest =
factory.create(
@@ -345,11 +350,16 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() {
val latest by collectLastValue(underTest.notificationChip)
assertThat(latest).isNotNull()
+ assertThat(latest!!.isAppVisible).isFalse()
+ assertThat(latest!!.lastAppVisibleTime).isNull()
}
@Test
- fun notificationChip_hidesWhenAppIsVisible() =
+ fun notificationChip_updatesWhenAppIsVisible() =
kosmos.runTest {
+ activityManagerRepository.fake.startingIsAppVisibleValue = false
+ fakeSystemClock.setCurrentTimeMillis(9000)
+
val underTest =
factory.create(
activeNotificationModel(
@@ -363,32 +373,39 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() {
val latest by collectLastValue(underTest.notificationChip)
- activityManagerRepository.fake.setIsAppVisible(UID, false)
- assertThat(latest).isNotNull()
+ activityManagerRepository.fake.setIsAppVisible(UID, isAppVisible = false)
+ assertThat(latest!!.isAppVisible).isFalse()
+ assertThat(latest!!.lastAppVisibleTime).isNull()
- activityManagerRepository.fake.setIsAppVisible(UID, true)
- assertThat(latest).isNull()
+ fakeSystemClock.setCurrentTimeMillis(11000)
+ activityManagerRepository.fake.setIsAppVisible(UID, isAppVisible = true)
+ assertThat(latest!!.isAppVisible).isTrue()
+ assertThat(latest!!.lastAppVisibleTime).isEqualTo(11000)
- activityManagerRepository.fake.setIsAppVisible(UID, false)
- assertThat(latest).isNotNull()
+ fakeSystemClock.setCurrentTimeMillis(13000)
+ activityManagerRepository.fake.setIsAppVisible(UID, isAppVisible = false)
+ assertThat(latest!!.isAppVisible).isFalse()
+ assertThat(latest!!.lastAppVisibleTime).isEqualTo(11000)
+
+ fakeSystemClock.setCurrentTimeMillis(15000)
+ activityManagerRepository.fake.setIsAppVisible(UID, isAppVisible = true)
+ assertThat(latest!!.isAppVisible).isTrue()
+ assertThat(latest!!.lastAppVisibleTime).isEqualTo(15000)
}
- // Note: This test is theoretically impossible because the notification key should contain the
- // UID, so if the UID changes then the key would also change and a new interactor would be
- // created. But, test it just in case.
@Test
- fun notificationChip_updatedUid_rechecksAppVisibility_oldObserverUnregistered() =
+ fun notificationChip_updatedUid_newUidIsIgnoredButOtherDataNotIgnored() =
kosmos.runTest {
activityManagerRepository.fake.startingIsAppVisibleValue = false
- val hiddenUid = 100
- val shownUid = 101
+ val originalUid = 100
+ val newUid = 101
val underTest =
factory.create(
activeNotificationModel(
key = "notif",
- uid = hiddenUid,
+ uid = originalUid,
statusBarChipIcon = mock(),
promotedContent = PROMOTED_CONTENT,
),
@@ -396,21 +413,39 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() {
)
val latest by collectLastValue(underTest.notificationChip)
assertThat(latest).isNotNull()
+ assertThat(latest!!.isAppVisible).isFalse()
// WHEN the notif gets a new UID that starts as visible
activityManagerRepository.fake.startingIsAppVisibleValue = true
+ val newPromotedContentBuilder =
+ PromotedNotificationContentModel.Builder("notif").apply {
+ this.shortCriticalText = "Arrived"
+ }
+ val newPromotedContent = newPromotedContentBuilder.build()
underTest.setNotification(
activeNotificationModel(
key = "notif",
- uid = shownUid,
+ uid = newUid,
statusBarChipIcon = mock(),
- promotedContent = PROMOTED_CONTENT,
+ promotedContent = newPromotedContent,
)
)
- // THEN we re-fetch the app visibility state with the new UID, and since that UID is
- // visible, we hide the chip
- assertThat(latest).isNull()
+ // THEN we do update other fields like promoted content
+ assertThat(latest!!.promotedContent).isEqualTo(newPromotedContent)
+
+ // THEN we don't fetch the app visibility state for the new UID
+ assertThat(latest!!.isAppVisible).isFalse()
+
+ // AND don't listen to updates for the new UID
+ activityManagerRepository.fake.setIsAppVisible(newUid, isAppVisible = false)
+ activityManagerRepository.fake.setIsAppVisible(newUid, isAppVisible = true)
+ assertThat(latest!!.isAppVisible).isFalse()
+
+ // AND we still use updates from the old UID
+ // TODO(b/364653005): This particular behavior isn't great, can we do better?
+ activityManagerRepository.fake.setIsAppVisible(originalUid, isAppVisible = true)
+ assertThat(latest!!.isAppVisible).isTrue()
}
companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
index e89c929a5827..7ed2bd38bcd2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
@@ -21,8 +21,8 @@ import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.coroutines.collectValues
+import com.android.systemui.activity.data.repository.activityManagerRepository
+import com.android.systemui.activity.data.repository.fake
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.collectValues
@@ -41,7 +41,6 @@ import com.android.systemui.testKosmos
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
-import kotlinx.coroutines.test.runTest
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
@@ -55,9 +54,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
@Test
@DisableFlags(StatusBarNotifChips.FLAG_NAME)
- fun notificationChips_flagOff_noNotifs() =
+ fun shownNotificationChips_flagOff_noNotifs() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
setNotifs(
listOf(
@@ -74,9 +73,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun notificationChips_noNotifs_empty() =
+ fun shownNotificationChips_noNotifs_empty() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
setNotifs(emptyList())
@@ -86,9 +85,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
@DisableFlags(StatusBarConnectedDisplays.FLAG_NAME)
- fun notificationChips_notifMissingStatusBarChipIconView_cdFlagOff_empty() =
+ fun shownNotificationChips_notifMissingStatusBarChipIconView_cdFlagOff_empty() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
setNotifs(
listOf(
@@ -105,9 +104,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME, StatusBarConnectedDisplays.FLAG_NAME)
- fun notificationChips_notifMissingStatusBarChipIconView_cdFlagOn_notEmpty() =
+ fun shownNotificationChips_notifMissingStatusBarChipIconView_cdFlagOn_notEmpty() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
setNotifs(
listOf(
@@ -124,9 +123,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun notificationChips_onePromotedNotif_statusBarIconViewMatches() =
+ fun shownNotificationChips_onePromotedNotif_statusBarIconViewMatches() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
val icon = mock<StatusBarIconView>()
setNotifs(
@@ -146,9 +145,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun notificationChips_onlyForPromotedNotifs() =
+ fun shownNotificationChips_onlyForPromotedNotifs() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
val firstIcon = mock<StatusBarIconView>()
val secondIcon = mock<StatusBarIconView>()
@@ -179,12 +178,42 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
assertThat(latest!![1].statusBarChipIconView).isEqualTo(secondIcon)
}
+ @Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun shownNotificationChips_onlyForNotVisibleApps() =
+ kosmos.runTest {
+ activityManagerRepository.fake.startingIsAppVisibleValue = false
+
+ val latest by collectLastValue(underTest.shownNotificationChips)
+
+ val uid = 433
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ uid = uid,
+ statusBarChipIcon = mock<StatusBarIconView>(),
+ promotedContent = PromotedNotificationContentModel.Builder("notif1").build(),
+ )
+ )
+ )
+
+ activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = false)
+ assertThat(latest).hasSize(1)
+
+ activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = true)
+ assertThat(latest).isEmpty()
+
+ activityManagerRepository.fake.setIsAppVisible(uid, isAppVisible = false)
+ assertThat(latest).hasSize(1)
+ }
+
/** Regression test for b/388521980. */
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun notificationChips_callNotifIsAlsoPromoted_callNotifExcluded() =
+ fun shownNotificationChips_callNotifIsAlsoPromoted_callNotifExcluded() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
setNotifs(
listOf(
@@ -212,9 +241,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun notificationChips_notifUpdatesGoThrough() =
+ fun shownNotificationChips_notifUpdatesGoThrough() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
val firstIcon = mock<StatusBarIconView>()
val secondIcon = mock<StatusBarIconView>()
@@ -262,9 +291,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun notificationChips_promotedNotifDisappearsThenReappears() =
+ fun shownNotificationChips_promotedNotifDisappearsThenReappears() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
setNotifs(
listOf(
@@ -304,9 +333,9 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun notificationChips_sortedBasedOnFirstAppearanceTime() =
+ fun shownNotificationChips_sortedByFirstAppearanceTime() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
val firstIcon = mock<StatusBarIconView>()
val secondIcon = mock<StatusBarIconView>()
@@ -320,8 +349,7 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
promotedContent = PromotedNotificationContentModel.Builder("notif1").build(),
)
setNotifs(listOf(notif1))
- assertThat(latest).hasSize(1)
- assertThat(latest!![0].key).isEqualTo("notif1")
+ assertThat(latest!!.map { it.key }).containsExactly("notif1").inOrder()
// WHEN we add notif2 at t=2000
fakeSystemClock.advanceTime(1000)
@@ -333,26 +361,20 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
)
setNotifs(listOf(notif1, notif2))
- // THEN notif2 is ranked above notif1 because it appeared later
- assertThat(latest).hasSize(2)
- assertThat(latest!![0].key).isEqualTo("notif2")
- assertThat(latest!![1].key).isEqualTo("notif1")
+ // THEN notif2 is ranked above notif1 because notif2 appeared later
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
// WHEN notif1 and notif2 swap places
setNotifs(listOf(notif2, notif1))
// THEN notif2 is still ranked above notif1 to preserve chip ordering
- assertThat(latest).hasSize(2)
- assertThat(latest!![0].key).isEqualTo("notif2")
- assertThat(latest!![1].key).isEqualTo("notif1")
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
// WHEN notif1 and notif2 swap places again
setNotifs(listOf(notif1, notif2))
// THEN notif2 is still ranked above notif1 to preserve chip ordering
- assertThat(latest).hasSize(2)
- assertThat(latest!![0].key).isEqualTo("notif2")
- assertThat(latest!![1].key).isEqualTo("notif1")
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
// WHEN notif1 gets an update
val notif1NewPromotedContent =
@@ -371,9 +393,7 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
)
// THEN notif2 is still ranked above notif1 to preserve chip ordering
- assertThat(latest).hasSize(2)
- assertThat(latest!![0].key).isEqualTo("notif2")
- assertThat(latest!![1].key).isEqualTo("notif1")
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
// WHEN notif1 disappears and then reappears
fakeSystemClock.advanceTime(1000)
@@ -384,16 +404,245 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
setNotifs(listOf(notif2, notif1))
// THEN notif1 is now ranked first
- assertThat(latest).hasSize(2)
- assertThat(latest!![0].key).isEqualTo("notif1")
- assertThat(latest!![1].key).isEqualTo("notif2")
+ assertThat(latest!!.map { it.key }).containsExactly("notif1", "notif2").inOrder()
+ }
+
+ @Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun shownNotificationChips_sortedByLastAppVisibleTime() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.shownNotificationChips)
+
+ val notif1Info = NotifInfo("notif1", mock<StatusBarIconView>(), uid = 100)
+ val notif2Info = NotifInfo("notif2", mock<StatusBarIconView>(), uid = 200)
+
+ activityManagerRepository.fake.startingIsAppVisibleValue = false
+ fakeSystemClock.setCurrentTimeMillis(1000)
+ val notif1 =
+ activeNotificationModel(
+ key = notif1Info.key,
+ uid = notif1Info.uid,
+ statusBarChipIcon = notif1Info.icon,
+ promotedContent =
+ PromotedNotificationContentModel.Builder(notif1Info.key).build(),
+ )
+ val notif2 =
+ activeNotificationModel(
+ key = notif2Info.key,
+ uid = notif2Info.uid,
+ statusBarChipIcon = notif2Info.icon,
+ promotedContent =
+ PromotedNotificationContentModel.Builder(notif2Info.key).build(),
+ )
+ setNotifs(listOf(notif1, notif2))
+ assertThat(latest!!.map { it.key }).containsExactly("notif1", "notif2").inOrder()
+
+ // WHEN notif2's app becomes visible
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = true)
+
+ // THEN notif2 is no longer shown
+ assertThat(latest!!.map { it.key }).containsExactly("notif1").inOrder()
+
+ // WHEN notif2's app is no longer visible
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = false)
+
+ // THEN notif2 is ranked above notif1 because it was more recently visible
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
+
+ // WHEN the app associated with notif1 becomes visible then un-visible
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif1Info.uid, isAppVisible = true)
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif1Info.uid, isAppVisible = false)
+
+ // THEN notif1 is now ranked above notif2 because it was more recently visible
+ assertThat(latest!!.map { it.key }).containsExactly("notif1", "notif2").inOrder()
+ }
+
+ @Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun shownNotificationChips_newNotificationTakesPriorityOverLastAppVisible() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.shownNotificationChips)
+
+ val notif1Info = NotifInfo("notif1", mock<StatusBarIconView>(), uid = 100)
+ val notif2Info = NotifInfo("notif2", mock<StatusBarIconView>(), uid = 200)
+ val notif3Info = NotifInfo("notif3", mock<StatusBarIconView>(), uid = 300)
+
+ activityManagerRepository.fake.startingIsAppVisibleValue = false
+ fakeSystemClock.setCurrentTimeMillis(1000)
+ val notif1 =
+ activeNotificationModel(
+ key = notif1Info.key,
+ uid = notif1Info.uid,
+ statusBarChipIcon = notif1Info.icon,
+ promotedContent =
+ PromotedNotificationContentModel.Builder(notif1Info.key).build(),
+ )
+ val notif2 =
+ activeNotificationModel(
+ key = notif2Info.key,
+ uid = notif2Info.uid,
+ statusBarChipIcon = notif2Info.icon,
+ promotedContent =
+ PromotedNotificationContentModel.Builder(notif2Info.key).build(),
+ )
+ setNotifs(listOf(notif1, notif2))
+ assertThat(latest!!.map { it.key }).containsExactly("notif1", "notif2").inOrder()
+
+ // WHEN notif2's app becomes visible then not visible
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = true)
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = false)
+
+ // THEN notif2 is ranked above notif1 because it was more recently visible
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
+
+ // WHEN a new notif3 appears
+ fakeSystemClock.advanceTime(1000)
+ val notif3 =
+ activeNotificationModel(
+ key = notif3Info.key,
+ uid = notif3Info.uid,
+ statusBarChipIcon = notif3Info.icon,
+ promotedContent =
+ PromotedNotificationContentModel.Builder(notif3Info.key).build(),
+ )
+ setNotifs(listOf(notif1, notif2, notif3))
+
+ // THEN notif3 is ranked above everything else
+ // AND notif2 is still before notif1 because it was more recently visible
+ assertThat(latest!!.map { it.key })
+ .containsExactly("notif3", "notif2", "notif1")
+ .inOrder()
+ }
+
+ @Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun shownNotificationChips_fullSort() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.shownNotificationChips)
+
+ val notif1Info = NotifInfo("notif1", mock<StatusBarIconView>(), uid = 100)
+ val notif2Info = NotifInfo("notif2", mock<StatusBarIconView>(), uid = 200)
+ val notif3Info = NotifInfo("notif3", mock<StatusBarIconView>(), uid = 300)
+
+ // First, add notif1 at t=1000
+ activityManagerRepository.fake.startingIsAppVisibleValue = false
+ fakeSystemClock.setCurrentTimeMillis(1000)
+ val notif1 =
+ activeNotificationModel(
+ key = notif1Info.key,
+ uid = notif1Info.uid,
+ statusBarChipIcon = notif1Info.icon,
+ promotedContent =
+ PromotedNotificationContentModel.Builder(notif1Info.key).build(),
+ )
+ setNotifs(listOf(notif1))
+
+ // WHEN we add notif2 at t=2000
+ fakeSystemClock.advanceTime(1000)
+ val notif2 =
+ activeNotificationModel(
+ key = notif2Info.key,
+ uid = notif2Info.uid,
+ statusBarChipIcon = notif2Info.icon,
+ promotedContent =
+ PromotedNotificationContentModel.Builder(notif2Info.key).build(),
+ )
+ setNotifs(listOf(notif1, notif2))
+
+ // THEN notif2 is ranked above notif1 because notif2 appeared later
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
+
+ // WHEN notif2's app becomes visible then un-visible
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = true)
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = false)
+
+ // THEN notif2 is ranked above notif1 because it was more recently visible
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif1").inOrder()
+
+ // WHEN the app associated with notif1 becomes visible then un-visible
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif1Info.uid, isAppVisible = true)
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif1Info.uid, isAppVisible = false)
+
+ // THEN notif1 is ranked above notif2 because it was more recently visible
+ assertThat(latest!!.map { it.key }).containsExactly("notif1", "notif2").inOrder()
+
+ // WHEN notif2 gets an update
+ val notif2NewPromotedContent =
+ PromotedNotificationContentModel.Builder("notif2").apply {
+ this.shortCriticalText = "Arrived"
+ }
+ setNotifs(
+ listOf(
+ notif1,
+ activeNotificationModel(
+ key = notif2Info.key,
+ uid = notif2Info.uid,
+ statusBarChipIcon = notif2Info.icon,
+ promotedContent = notif2NewPromotedContent.build(),
+ ),
+ )
+ )
+
+ // THEN notif1 is still ranked above notif2 to preserve chip ordering
+ assertThat(latest!!.map { it.key }).containsExactly("notif1", "notif2").inOrder()
+
+ // WHEN a new notification appears
+ fakeSystemClock.advanceTime(1000)
+ val notif3 =
+ activeNotificationModel(
+ key = notif3Info.key,
+ uid = notif3Info.uid,
+ statusBarChipIcon = notif3Info.icon,
+ promotedContent =
+ PromotedNotificationContentModel.Builder(notif3Info.key).build(),
+ )
+ setNotifs(listOf(notif1, notif2, notif3))
+
+ // THEN it's ranked first because it's new
+ assertThat(latest!!.map { it.key })
+ .containsExactly("notif3", "notif1", "notif2")
+ .inOrder()
+
+ // WHEN notif2 becomes visible then un-visible again
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = true)
+ fakeSystemClock.advanceTime(1000)
+ activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = false)
+
+ // THEN it moves to the front
+ assertThat(latest!!.map { it.key })
+ .containsExactly("notif2", "notif3", "notif1")
+ .inOrder()
+
+ // WHEN notif1 disappears and then reappears
+ fakeSystemClock.advanceTime(1000)
+ setNotifs(listOf(notif2, notif3))
+ assertThat(latest!!.map { it.key }).containsExactly("notif2", "notif3").inOrder()
+
+ fakeSystemClock.advanceTime(1000)
+ setNotifs(listOf(notif2, notif1, notif3))
+
+ // THEN notif1 is now ranked first
+ assertThat(latest!!.map { it.key })
+ .containsExactly("notif1", "notif2", "notif3")
+ .inOrder()
}
@Test
@EnableFlags(StatusBarNotifChips.FLAG_NAME)
- fun notificationChips_notifChangesKey() =
+ fun shownNotificationChips_notifChangesKey() =
kosmos.runTest {
- val latest by collectLastValue(underTest.notificationChips)
+ val latest by collectLastValue(underTest.shownNotificationChips)
val firstIcon = mock<StatusBarIconView>()
val secondIcon = mock<StatusBarIconView>()
@@ -466,4 +715,6 @@ class StatusBarNotificationChipsInteractorTest : SysuiTestCase() {
.apply { notifs.forEach { addIndividualNotif(it) } }
.build()
}
+
+ private data class NotifInfo(val key: String, val icon: StatusBarIconView, val uid: Int)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
index aaa9b58a45df..7cf817a06225 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
@@ -49,8 +49,11 @@ import com.android.systemui.statusbar.notification.shared.ActiveNotificationMode
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.testKosmos
+import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
+import kotlin.time.Duration.Companion.minutes
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Before
import org.junit.runner.RunWith
@@ -286,13 +289,15 @@ class NotifChipsViewModelTest : SysuiTestCase() {
fun chips_hasShortCriticalText_usesTextInsteadOfTime() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.shortCriticalText = "Arrived"
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 30.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.BasicTime,
)
}
@@ -340,13 +345,15 @@ class NotifChipsViewModelTest : SysuiTestCase() {
fun chips_basicTime_timeHiddenIfAutomaticallyPromoted() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.wasPromotedAutomatically = true
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 30.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.BasicTime,
)
}
@@ -370,13 +377,15 @@ class NotifChipsViewModelTest : SysuiTestCase() {
fun chips_basicTime_timeShownIfNotAutomaticallyPromoted() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.wasPromotedAutomatically = false
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 30.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.BasicTime,
)
}
@@ -397,18 +406,117 @@ class NotifChipsViewModelTest : SysuiTestCase() {
@Test
@DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
- fun chips_basicTime_isShortTimeDelta() =
+ fun chips_basicTime_timeInFuture_isShortTimeDelta() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 3.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 13.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.BasicTime,
)
}
+
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = promotedContentBuilder.build(),
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0])
+ .isInstanceOf(OngoingActivityChipModel.Active.ShortTimeDelta::class.java)
+ }
+
+ @Test
+ @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
+ fun chips_basicTime_timeLessThanOneMinInFuture_isIconOnly() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.chips)
+ val currentTime = 3.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
+
+ val promotedContentBuilder =
+ PromotedNotificationContentModel.Builder("notif").apply {
+ this.time =
+ PromotedNotificationContentModel.When(
+ time = currentTime + 500,
+ mode = PromotedNotificationContentModel.When.Mode.BasicTime,
+ )
+ }
+
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = promotedContentBuilder.build(),
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0])
+ .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
+ }
+
+ @Test
+ @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
+ fun chips_basicTime_timeIsNow_isIconOnly() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.chips)
+ val currentTime = 62.seconds.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
+
+ val promotedContentBuilder =
+ PromotedNotificationContentModel.Builder("notif").apply {
+ this.time =
+ PromotedNotificationContentModel.When(
+ time = currentTime,
+ mode = PromotedNotificationContentModel.When.Mode.BasicTime,
+ )
+ }
+
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = promotedContentBuilder.build(),
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0])
+ .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
+ }
+
+ @Test
+ @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
+ fun chips_basicTime_timeInPast_isIconOnly() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.chips)
+ val currentTime = 62.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
+
+ val promotedContentBuilder =
+ PromotedNotificationContentModel.Builder("notif").apply {
+ this.time =
+ PromotedNotificationContentModel.When(
+ time = currentTime - 2.minutes.inWholeMilliseconds,
+ mode = PromotedNotificationContentModel.When.Mode.BasicTime,
+ )
+ }
+
setNotifs(
listOf(
activeNotificationModel(
@@ -421,6 +529,45 @@ class NotifChipsViewModelTest : SysuiTestCase() {
assertThat(latest).hasSize(1)
assertThat(latest!![0])
+ .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java)
+ }
+
+ // Not necessarily the behavior we *want* to have, but it's the currently implemented behavior.
+ @Test
+ @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
+ fun chips_basicTime_timeIsInFuture_thenTimeAdvances_stillShortTimeDelta() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
+
+ val promotedContentBuilder =
+ PromotedNotificationContentModel.Builder("notif").apply {
+ this.time =
+ PromotedNotificationContentModel.When(
+ time = currentTime + 3.minutes.inWholeMilliseconds,
+ mode = PromotedNotificationContentModel.When.Mode.BasicTime,
+ )
+ }
+
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ promotedContent = promotedContentBuilder.build(),
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0])
+ .isInstanceOf(OngoingActivityChipModel.Active.ShortTimeDelta::class.java)
+
+ fakeSystemClock.advanceTime(5.minutes.inWholeMilliseconds)
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0])
.isInstanceOf(OngoingActivityChipModel.Active.ShortTimeDelta::class.java)
}
@@ -429,12 +576,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
fun chips_countUpTime_isTimer() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 10.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.CountUp,
)
}
@@ -457,12 +606,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
fun chips_countDownTime_isTimer() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 10.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.CountDown,
)
}
@@ -485,12 +636,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
fun chips_noHeadsUp_showsTime() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 10.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.BasicTime,
)
}
@@ -517,12 +670,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
fun chips_hasHeadsUpBySystem_showsTime() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 10.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.BasicTime,
)
}
@@ -556,12 +711,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
fun chips_hasHeadsUpByUser_forOtherNotif_showsTime() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 10.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.BasicTime,
)
}
@@ -569,7 +726,7 @@ class NotifChipsViewModelTest : SysuiTestCase() {
PromotedNotificationContentModel.Builder("other notif").apply {
this.time =
PromotedNotificationContentModel.When(
- time = 654321L,
+ time = currentTime + 10.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.BasicTime,
)
}
@@ -610,12 +767,14 @@ class NotifChipsViewModelTest : SysuiTestCase() {
fun chips_hasHeadsUpByUser_forThisNotif_onlyShowsIcon() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
+ val currentTime = 30.minutes.inWholeMilliseconds
+ fakeSystemClock.setCurrentTimeMillis(currentTime)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
this.time =
PromotedNotificationContentModel.When(
- time = 6543L,
+ time = currentTime + 10.minutes.inWholeMilliseconds,
mode = PromotedNotificationContentModel.When.Mode.BasicTime,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingStateTest.kt
new file mode 100644
index 000000000000..5dc59e893715
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingStateTest.kt
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.R.string.duration_hours_medium
+import com.android.internal.R.string.duration_minutes_medium
+import com.android.internal.R.string.now_string_shortest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.minutes
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TimeRemainingStateTest : SysuiTestCase() {
+
+ private var fakeTimeSource: MutableTimeSource = MutableTimeSource()
+ // We need a non-zero start time to advance to. This is needed to ensure `TimeRemainingState` is
+ // updated at least once.
+ private val startTime = 1.seconds.inWholeMilliseconds
+
+ @Test
+ fun timeRemainingState_pastTime() = runTest {
+ val state = TimeRemainingState(fakeTimeSource, startTime - 62.seconds.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ fakeTimeSource.time = startTime
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData).isNull()
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_lessThanOneMinute() = runTest {
+ val state = TimeRemainingState(fakeTimeSource, startTime + 59.seconds.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ fakeTimeSource.time = startTime
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(now_string_shortest)
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_lessThanOneMinuteInThePast() = runTest {
+ val state = TimeRemainingState(fakeTimeSource, startTime - 59.seconds.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ fakeTimeSource.time = startTime
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(now_string_shortest)
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_oneMinute() = runTest {
+ val state = TimeRemainingState(fakeTimeSource, startTime + 60.seconds.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ fakeTimeSource.time = startTime
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_minutes_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(1)
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_lessThanOneHour() = runTest {
+ val state = TimeRemainingState(fakeTimeSource, startTime + 59.minutes.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ fakeTimeSource.time = startTime
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_minutes_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(59)
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_oneHour() = runTest {
+ val state = TimeRemainingState(fakeTimeSource, startTime + 60.minutes.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ fakeTimeSource.time = startTime
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_hours_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(1)
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_betweenOneAndTwoHours() = runTest {
+ val state = TimeRemainingState(fakeTimeSource, startTime + 119.minutes.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ fakeTimeSource.time = startTime
+ advanceTimeBy(startTime)
+
+ assertThat(state.timeRemainingData).isNotNull()
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_hours_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(1)
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_betweenFiveAndSixHours() = runTest {
+ val state = TimeRemainingState(fakeTimeSource, startTime + 320.minutes.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ fakeTimeSource.time = startTime
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_hours_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(5)
+ job.cancelAndJoin()
+ }
+
+ fun timeRemainingState_moreThan24Hours() = runTest {
+ val state =
+ TimeRemainingState(fakeTimeSource, startTime + (25 * 60.minutes.inWholeMilliseconds))
+ val job = launch { state.run() }
+
+ fakeTimeSource.time = startTime
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData).isNull()
+
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_updateFromMinuteToNow() = runTest {
+ fakeTimeSource.time = startTime
+ val state = TimeRemainingState(fakeTimeSource, startTime + 119.seconds.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_minutes_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(1)
+
+ fakeTimeSource.time += 59.seconds.inWholeMilliseconds
+ advanceTimeBy(59.seconds.inWholeMilliseconds)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_minutes_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(1)
+
+ fakeTimeSource.time += 1.seconds.inWholeMilliseconds
+ advanceTimeBy(1.seconds.inWholeMilliseconds)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(now_string_shortest)
+
+ job.cancelAndJoin()
+ }
+
+ fun timeRemainingState_updateFromNowToEmpty() = runTest {
+ fakeTimeSource.time = startTime
+ val state = TimeRemainingState(fakeTimeSource, startTime)
+ val job = launch { state.run() }
+
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(now_string_shortest)
+
+ fakeTimeSource.time += 62.seconds.inWholeMilliseconds
+ advanceTimeBy(62.seconds.inWholeMilliseconds)
+ assertThat(state.timeRemainingData).isNull()
+
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_updateFromHourToMinutes() = runTest {
+ fakeTimeSource.time = startTime
+ val state = TimeRemainingState(fakeTimeSource, startTime + 119.minutes.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_hours_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(1)
+
+ fakeTimeSource.time += 59.minutes.inWholeMilliseconds
+ advanceTimeBy(59.minutes.inWholeMilliseconds)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_hours_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(1)
+
+ fakeTimeSource.time += 1.seconds.inWholeMilliseconds
+ advanceTimeBy(1.seconds.inWholeMilliseconds)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_minutes_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(59)
+
+ job.cancelAndJoin()
+ }
+
+ @Test
+ fun timeRemainingState_showAfterLessThan24Hours() = runTest {
+ fakeTimeSource.time = startTime
+ val state = TimeRemainingState(fakeTimeSource, startTime + 25.hours.inWholeMilliseconds)
+ val job = launch { state.run() }
+
+ advanceTimeBy(startTime)
+ assertThat(state.timeRemainingData).isNull()
+
+ fakeTimeSource.time += 1.hours.inWholeMilliseconds + 1.seconds.inWholeMilliseconds
+ advanceTimeBy(1.hours.inWholeMilliseconds + 1.seconds.inWholeMilliseconds)
+ assertThat(state.timeRemainingData!!.first).isEqualTo(duration_hours_medium)
+ assertThat(state.timeRemainingData!!.second).isEqualTo(23)
+
+ job.cancelAndJoin()
+ }
+
+ /** A fake implementation of [TimeSource] that allows the caller to set the current time */
+ private class MutableTimeSource(var time: Long = 0L) : TimeSource {
+ override fun getCurrentTime(): Long {
+ return time
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorTest.kt
index 1a5f57dd43f8..6409a20d5156 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractorTest.kt
@@ -17,100 +17,119 @@
package com.android.systemui.statusbar.featurepods.media.domain.interactor
import android.graphics.drawable.Drawable
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.parameterizeSceneContainerFlag
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
import com.android.systemui.media.controls.shared.model.MediaAction
import com.android.systemui.media.controls.shared.model.MediaButton
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.MockitoAnnotations
import org.mockito.kotlin.mock
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+@RunWith(ParameterizedAndroidJunit4::class)
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class MediaControlChipInteractorTest : SysuiTestCase() {
-
+class MediaControlChipInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
private val kosmos = testKosmos().useUnconfinedTestDispatcher()
- private val underTest = kosmos.mediaControlChipInteractor
+ private val mediaFilterRepository = kosmos.mediaFilterRepository
+ private val Kosmos.underTest by Kosmos.Fixture { kosmos.mediaControlChipInteractor }
+ @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return parameterizeSceneContainerFlag()
+ }
+ }
+
+ @Before
+ fun setUp() {
+ kosmos.underTest.initialize()
+ MockitoAnnotations.initMocks(this)
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags)
+ }
@Test
- fun mediaControlModel_noActiveMedia_null() =
+ fun mediaControlChipModel_noActiveMedia_null() =
kosmos.runTest {
- val model by collectLastValue(underTest.mediaControlModel)
+ val model by collectLastValue(underTest.mediaControlChipModel)
assertThat(model).isNull()
}
@Test
- fun mediaControlModel_activeMedia_notNull() =
+ fun mediaControlChipModel_activeMedia_notNull() =
kosmos.runTest {
- val model by collectLastValue(underTest.mediaControlModel)
+ val model by collectLastValue(underTest.mediaControlChipModel)
val userMedia = MediaData(active = true)
- val instanceId = userMedia.instanceId
- mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
- mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+ updateMedia(userMedia)
assertThat(model).isNotNull()
}
@Test
- fun mediaControlModel_mediaRemoved_null() =
+ fun mediaControlChipModel_mediaRemoved_null() =
kosmos.runTest {
- val model by collectLastValue(underTest.mediaControlModel)
+ val model by collectLastValue(underTest.mediaControlChipModel)
val userMedia = MediaData(active = true)
- val instanceId = userMedia.instanceId
- mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
- mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+ updateMedia(userMedia)
assertThat(model).isNotNull()
- assertThat(mediaFilterRepository.removeSelectedUserMediaEntry(instanceId, userMedia))
- .isTrue()
- mediaFilterRepository.addMediaDataLoadingState(
- MediaDataLoadingModel.Removed(instanceId)
- )
+ removeMedia(userMedia)
assertThat(model).isNull()
}
@Test
- fun mediaControlModel_songNameChanged_emitsUpdatedModel() =
+ fun mediaControlChipModel_songNameChanged_emitsUpdatedModel() =
kosmos.runTest {
- val model by collectLastValue(underTest.mediaControlModel)
+ val model by collectLastValue(underTest.mediaControlChipModel)
val initialSongName = "Initial Song"
val newSongName = "New Song"
val userMedia = MediaData(active = true, song = initialSongName)
- val instanceId = userMedia.instanceId
- mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
- mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+ updateMedia(userMedia)
assertThat(model).isNotNull()
assertThat(model?.songName).isEqualTo(initialSongName)
val updatedUserMedia = userMedia.copy(song = newSongName)
- mediaFilterRepository.addSelectedUserMediaEntry(updatedUserMedia)
+ updateMedia(updatedUserMedia)
assertThat(model?.songName).isEqualTo(newSongName)
}
@Test
- fun mediaControlModel_playPauseActionChanges_emitsUpdatedModel() =
+ fun mediaControlChipModel_playPauseActionChanges_emitsUpdatedModel() =
kosmos.runTest {
- val model by collectLastValue(underTest.mediaControlModel)
+ val model by collectLastValue(underTest.mediaControlChipModel)
val mockDrawable = mock<Drawable>()
@@ -123,9 +142,7 @@ class MediaControlChipInteractorTest : SysuiTestCase() {
)
val mediaButton = MediaButton(playOrPause = initialAction)
val userMedia = MediaData(active = true, semanticActions = mediaButton)
- val instanceId = userMedia.instanceId
- mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
- mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+ updateMedia(userMedia)
assertThat(model).isNotNull()
assertThat(model?.playOrPause).isEqualTo(initialAction)
@@ -139,15 +156,15 @@ class MediaControlChipInteractorTest : SysuiTestCase() {
)
val updatedMediaButton = MediaButton(playOrPause = newAction)
val updatedUserMedia = userMedia.copy(semanticActions = updatedMediaButton)
- mediaFilterRepository.addSelectedUserMediaEntry(updatedUserMedia)
+ updateMedia(updatedUserMedia)
assertThat(model?.playOrPause).isEqualTo(newAction)
}
@Test
- fun mediaControlModel_playPauseActionRemoved_playPauseNull() =
+ fun mediaControlChipModel_playPauseActionRemoved_playPauseNull() =
kosmos.runTest {
- val model by collectLastValue(underTest.mediaControlModel)
+ val model by collectLastValue(underTest.mediaControlChipModel)
val mockDrawable = mock<Drawable>()
@@ -160,16 +177,36 @@ class MediaControlChipInteractorTest : SysuiTestCase() {
)
val mediaButton = MediaButton(playOrPause = initialAction)
val userMedia = MediaData(active = true, semanticActions = mediaButton)
- val instanceId = userMedia.instanceId
- mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
- mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+ updateMedia(userMedia)
assertThat(model).isNotNull()
assertThat(model?.playOrPause).isEqualTo(initialAction)
val updatedUserMedia = userMedia.copy(semanticActions = MediaButton())
- mediaFilterRepository.addSelectedUserMediaEntry(updatedUserMedia)
+ updateMedia(updatedUserMedia)
assertThat(model?.playOrPause).isNull()
}
+
+ private fun updateMedia(mediaData: MediaData) {
+ if (SceneContainerFlag.isEnabled) {
+ val instanceId = mediaData.instanceId
+ mediaFilterRepository.addSelectedUserMediaEntry(mediaData)
+ mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+ } else {
+ kosmos.underTest.updateMediaControlChipModelLegacy(mediaData)
+ }
+ }
+
+ private fun removeMedia(mediaData: MediaData) {
+ if (SceneContainerFlag.isEnabled) {
+ val instanceId = mediaData.instanceId
+ mediaFilterRepository.removeSelectedUserMediaEntry(instanceId, mediaData)
+ mediaFilterRepository.addMediaDataLoadingState(
+ MediaDataLoadingModel.Removed(instanceId)
+ )
+ } else {
+ kosmos.underTest.updateMediaControlChipModelLegacy(null)
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt
index 8650e4b8cfce..d36dbbe8d36f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt
@@ -16,26 +16,57 @@
package com.android.systemui.statusbar.featurepods.media.ui.viewmodel
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.parameterizeSceneContainerFlag
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.statusbar.featurepods.media.domain.interactor.mediaControlChipInteractor
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
+import org.junit.Before
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.MockitoAnnotations
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
-class MediaControlChipViewModelTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
private val kosmos = testKosmos().useUnconfinedTestDispatcher()
- private val underTest = kosmos.mediaControlChipViewModel
+ private val mediaControlChipInteractor by lazy { kosmos.mediaControlChipInteractor }
+ private val Kosmos.underTest by Kosmos.Fixture { kosmos.mediaControlChipViewModel }
+ @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return parameterizeSceneContainerFlag()
+ }
+ }
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ mediaControlChipInteractor.initialize()
+ }
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags)
+ }
@Test
fun chip_noActiveMedia_IsHidden() =
@@ -51,10 +82,7 @@ class MediaControlChipViewModelTest : SysuiTestCase() {
val chip by collectLastValue(underTest.chip)
val userMedia = MediaData(active = true, song = "test")
- val instanceId = userMedia.instanceId
-
- mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
- mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+ updateMedia(userMedia)
assertThat(chip).isInstanceOf(PopupChipModel.Shown::class.java)
}
@@ -67,16 +95,25 @@ class MediaControlChipViewModelTest : SysuiTestCase() {
val initialSongName = "Initial Song"
val newSongName = "New Song"
val userMedia = MediaData(active = true, song = initialSongName)
- val instanceId = userMedia.instanceId
-
- mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
- mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
-
+ updateMedia(userMedia)
+ assertThat(chip).isInstanceOf(PopupChipModel.Shown::class.java)
assertThat((chip as PopupChipModel.Shown).chipText).isEqualTo(initialSongName)
val updatedUserMedia = userMedia.copy(song = newSongName)
- mediaFilterRepository.addSelectedUserMediaEntry(updatedUserMedia)
+ updateMedia(updatedUserMedia)
assertThat((chip as PopupChipModel.Shown).chipText).isEqualTo(newSongName)
}
+
+ private fun updateMedia(mediaData: MediaData) {
+ if (SceneContainerFlag.isEnabled) {
+ val instanceId = mediaData.instanceId
+ kosmos.mediaFilterRepository.addSelectedUserMediaEntry(mediaData)
+ kosmos.mediaFilterRepository.addMediaDataLoadingState(
+ MediaDataLoadingModel.Loaded(instanceId)
+ )
+ } else {
+ mediaControlChipInteractor.updateMediaControlChipModelLegacy(mediaData)
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
index d66b010daefd..a58f7f72f08a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
@@ -51,8 +51,10 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.people.NotificationPersonExtractor;
import com.android.systemui.util.DeviceConfigProxyFake;
+import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
index 77fd06757595..8520508c7611 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
@@ -132,7 +132,7 @@ public class DynamicChildBindControllerTest extends SysuiTestCase {
LayoutInflater inflater = LayoutInflater.from(mContext);
inflater.setFactory2(
new RowInflaterTask.RowAsyncLayoutInflater(entry, new FakeSystemClock(), mock(
- RowInflaterTaskLogger.class)));
+ RowInflaterTaskLogger.class), mContext.getUser()));
ExpandableNotificationRow row = (ExpandableNotificationRow)
inflater.inflate(R.layout.status_bar_notification_row, null);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt
new file mode 100644
index 000000000000..426af264da07
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection
+
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class BundleEntryTest : SysuiTestCase() {
+ private lateinit var underTest: BundleEntry
+
+ @get:Rule
+ val setFlagsRule = SetFlagsRule()
+
+ @Before
+ fun setUp() {
+ underTest = BundleEntry("key")
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun getParent_adapter() {
+ assertThat(underTest.entryAdapter.parent).isEqualTo(GroupEntry.ROOT_ENTRY)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isTopLevelEntry_adapter() {
+ assertThat(underTest.entryAdapter.isTopLevelEntry).isTrue()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun getRow_adapter() {
+ assertThat(underTest.entryAdapter.row).isNull()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun getGroupRoot_adapter() {
+ assertThat(underTest.entryAdapter.groupRoot).isEqualTo(underTest.entryAdapter)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun getKey_adapter() {
+ assertThat(underTest.entryAdapter.key).isEqualTo("key")
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 8e95ac599ce1..76e2d619a4df 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -30,6 +30,9 @@ import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.NotificationChannel;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -39,8 +42,10 @@ import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -57,6 +62,9 @@ public class HighPriorityProviderTest extends SysuiTestCase {
@Mock private GroupMembershipManager mGroupMembershipManager;
private HighPriorityProvider mHighPriorityProvider;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -210,6 +218,7 @@ public class HighPriorityProviderTest extends SysuiTestCase {
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
public void testIsHighPriority_checkChildrenToCalculatePriority_legacy() {
// GIVEN: a summary with low priority has a highPriorityChild and a lowPriorityChild
final NotificationEntry summary = createNotifEntry(false);
@@ -247,20 +256,18 @@ public class HighPriorityProviderTest extends SysuiTestCase {
}
@Test
- public void testIsHighPriority_checkChildrenToCalculatePriority() {
+ public void testIsHighPriority_checkChildrenViewsToCalculatePriority() {
// GIVEN:
// parent with summary = lowPrioritySummary
// NotificationEntry = lowPriorityChild
// NotificationEntry = highPriorityChild
+ List<NotificationEntry> children = List.of(createNotifEntry(false), createNotifEntry(true));
final NotificationEntry lowPrioritySummary = createNotifEntry(false);
final GroupEntry parentEntry = new GroupEntryBuilder()
.setSummary(lowPrioritySummary)
+ .setChildren(children)
.build();
- when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn(
- new ArrayList<>(
- List.of(
- createNotifEntry(false),
- createNotifEntry(true))));
+ when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn(children);
// THEN the GroupEntry parentEntry is high priority since it has a high priority child
assertTrue(mHighPriorityProvider.isHighPriority(parentEntry));
@@ -272,10 +279,11 @@ public class HighPriorityProviderTest extends SysuiTestCase {
// parent with summary = lowPrioritySummary
// NotificationEntry = lowPriorityChild
final NotificationEntry lowPrioritySummary = createNotifEntry(false);
+ final NotificationEntry lowPriorityChild = createNotifEntry(false);
final GroupEntry parentEntry = new GroupEntryBuilder()
.setSummary(lowPrioritySummary)
+ .setChildren(List.of(lowPriorityChild))
.build();
- final NotificationEntry lowPriorityChild = createNotifEntry(false);
when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn(
new ArrayList<>(List.of(lowPriorityChild)));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
deleted file mode 100644
index 544d20145db3..000000000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.coordinator;
-
-import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
-import static android.app.Notification.FLAG_PROMOTED_ONGOING;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Person;
-import android.content.Intent;
-import android.graphics.Color;
-import android.os.UserHandle;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
-import android.testing.TestableLooper;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
-import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@TestableLooper.RunWithLooper
-public class ColorizedFgsCoordinatorTest extends SysuiTestCase {
-
- private static final int NOTIF_USER_ID = 0;
- @Mock private NotifPipeline mNotifPipeline;
-
- private NotificationEntryBuilder mEntryBuilder;
- private ColorizedFgsCoordinator mColorizedFgsCoordinator;
- private NotifSectioner mFgsSection;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- allowTestableLooperAsMainThread();
-
- mColorizedFgsCoordinator = new ColorizedFgsCoordinator();
-
- mEntryBuilder = new NotificationEntryBuilder()
- .setUser(new UserHandle(NOTIF_USER_ID));
-
- mColorizedFgsCoordinator.attach(mNotifPipeline);
-
- mFgsSection = mColorizedFgsCoordinator.getSectioner();
- }
-
- @Test
- public void testIncludeFGSInSection_importanceDefault() {
- // GIVEN the notification represents a colorized foreground service with > min importance
- mEntryBuilder
- .setFlag(mContext, FLAG_FOREGROUND_SERVICE, true)
- .setImportance(IMPORTANCE_DEFAULT)
- .modifyNotification(mContext)
- .setColorized(true).setColor(Color.WHITE);
-
- // THEN the entry is in the fgs section
- assertTrue(mFgsSection.isInSection(mEntryBuilder.build()));
- }
-
- @Test
- public void testDiscludeFGSInSection_importanceMin() {
- // GIVEN the notification represents a colorized foreground service with min importance
- mEntryBuilder
- .setFlag(mContext, FLAG_FOREGROUND_SERVICE, true)
- .setImportance(IMPORTANCE_MIN)
- .modifyNotification(mContext)
- .setColorized(true).setColor(Color.WHITE);
-
- // THEN the entry is NOT in the fgs section
- assertFalse(mFgsSection.isInSection(mEntryBuilder.build()));
- }
-
- @Test
- public void testDiscludeNonFGSInSection() {
- // GIVEN the notification represents a colorized notification with high importance that
- // is NOT a foreground service
- mEntryBuilder
- .setImportance(IMPORTANCE_HIGH)
- .setFlag(mContext, FLAG_FOREGROUND_SERVICE, false)
- .modifyNotification(mContext).setColorized(false);
-
- // THEN the entry is NOT in the fgs section
- assertFalse(mFgsSection.isInSection(mEntryBuilder.build()));
- }
-
- @Test
- public void testIncludeCallInSection_importanceDefault() {
- // GIVEN the notification represents a call with > min importance
- mEntryBuilder
- .setImportance(IMPORTANCE_DEFAULT)
- .modifyNotification(mContext)
- .setStyle(makeCallStyle());
-
- // THEN the entry is in the fgs section
- assertTrue(mFgsSection.isInSection(mEntryBuilder.build()));
- }
-
- @Test
- public void testDiscludeCallInSection_importanceMin() {
- // GIVEN the notification represents a call with min importance
- mEntryBuilder
- .setImportance(IMPORTANCE_MIN)
- .modifyNotification(mContext)
- .setStyle(makeCallStyle());
-
- // THEN the entry is NOT in the fgs section
- assertFalse(mFgsSection.isInSection(mEntryBuilder.build()));
- }
-
- @Test
- @EnableFlags(PromotedNotificationUi.FLAG_NAME)
- public void testIncludePromotedOngoingInSection_flagEnabled() {
- // GIVEN the notification has FLAG_PROMOTED_ONGOING
- mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, true);
-
- // THEN the entry is in the fgs section
- assertTrue(mFgsSection.isInSection(mEntryBuilder.build()));
- }
-
- @Test
- @DisableFlags(PromotedNotificationUi.FLAG_NAME)
- public void testDiscludePromotedOngoingInSection_flagDisabled() {
- // GIVEN the notification has FLAG_PROMOTED_ONGOING
- mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, true);
-
- // THEN the entry is NOT in the fgs section
- assertFalse(mFgsSection.isInSection(mEntryBuilder.build()));
- }
-
- @Test
- @EnableFlags(PromotedNotificationUi.FLAG_NAME)
- public void promoterSelectsPromotedOngoing_flagEnabled() {
- ArgumentCaptor<NotifPromoter> captor = ArgumentCaptor.forClass(NotifPromoter.class);
- verify(mNotifPipeline).addPromoter(captor.capture());
- NotifPromoter promoter = captor.getValue();
-
- // GIVEN the notification has FLAG_PROMOTED_ONGOING
- mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, true);
-
- // THEN the entry is promoted to top level
- assertTrue(promoter.shouldPromoteToTopLevel(mEntryBuilder.build()));
- }
-
- @Test
- @EnableFlags(PromotedNotificationUi.FLAG_NAME)
- public void promoterIgnoresNonPromotedOngoing_flagEnabled() {
- ArgumentCaptor<NotifPromoter> captor = ArgumentCaptor.forClass(NotifPromoter.class);
- verify(mNotifPipeline).addPromoter(captor.capture());
- NotifPromoter promoter = captor.getValue();
-
- // GIVEN the notification does not have FLAG_PROMOTED_ONGOING
- mEntryBuilder.setFlag(mContext, FLAG_PROMOTED_ONGOING, false);
-
- // THEN the entry is NOT promoted to top level
- assertFalse(promoter.shouldPromoteToTopLevel(mEntryBuilder.build()));
- }
-
- @Test
- @DisableFlags(PromotedNotificationUi.FLAG_NAME)
- public void noPromoterAdded_flagDisabled() {
- verify(mNotifPipeline, never()).addPromoter(any());
- }
-
- private Notification.CallStyle makeCallStyle() {
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent("action"), PendingIntent.FLAG_IMMUTABLE);
- final Person person = new Person.Builder().setName("person").build();
- return Notification.CallStyle.forIncomingCall(person, pendingIntent, pendingIntent);
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt
new file mode 100644
index 000000000000..7fa157fa7cb3
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.Person
+import android.content.Intent
+import android.graphics.Color
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.core.StatusBarRootModernization
+import com.android.systemui.statusbar.notification.buildNotificationEntry
+import com.android.systemui.statusbar.notification.buildOngoingCallEntry
+import com.android.systemui.statusbar.notification.buildPromotedOngoingEntry
+import com.android.systemui.statusbar.notification.collection.buildEntry
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+import com.android.systemui.statusbar.notification.collection.notifPipeline
+import com.android.systemui.statusbar.notification.domain.interactor.renderNotificationListInteractor
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
+import com.android.systemui.statusbar.notification.promoted.domain.interactor.promotedNotificationsInteractor
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class ColorizedFgsCoordinatorTest : SysuiTestCase() {
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val notifPipeline
+ get() = kosmos.notifPipeline
+
+ private lateinit var colorizedFgsCoordinator: ColorizedFgsCoordinator
+ private lateinit var sectioner: NotifSectioner
+
+ @Before
+ fun setup() {
+ allowTestableLooperAsMainThread()
+
+ kosmos.statusBarNotificationChipsInteractor.start()
+
+ colorizedFgsCoordinator =
+ ColorizedFgsCoordinator(
+ kosmos.applicationCoroutineScope,
+ kosmos.promotedNotificationsInteractor,
+ )
+ colorizedFgsCoordinator.attach(notifPipeline)
+ sectioner = colorizedFgsCoordinator.sectioner
+ }
+
+ @Test
+ fun testIncludeFGSInSection_importanceDefault() {
+ // GIVEN the notification represents a colorized foreground service with > min importance
+ val entry = buildEntry {
+ setFlag(mContext, Notification.FLAG_FOREGROUND_SERVICE, true)
+ setImportance(NotificationManager.IMPORTANCE_DEFAULT)
+ modifyNotification(mContext).setColorized(true).setColor(Color.WHITE)
+ }
+
+ // THEN the entry is in the fgs section
+ assertTrue(sectioner.isInSection(entry))
+ }
+
+ @Test
+ fun testDiscludeFGSInSection_importanceMin() {
+ // GIVEN the notification represents a colorized foreground service with min importance
+ val entry = buildEntry {
+ setFlag(mContext, Notification.FLAG_FOREGROUND_SERVICE, true)
+ setImportance(NotificationManager.IMPORTANCE_MIN)
+ modifyNotification(mContext).setColorized(true).setColor(Color.WHITE)
+ }
+
+ // THEN the entry is NOT in the fgs section
+ assertFalse(sectioner.isInSection(entry))
+ }
+
+ @Test
+ fun testDiscludeNonFGSInSection() {
+ // GIVEN the notification represents a colorized notification with high importance that
+ // is NOT a foreground service
+ val entry = buildEntry {
+ setImportance(NotificationManager.IMPORTANCE_HIGH)
+ setFlag(mContext, Notification.FLAG_FOREGROUND_SERVICE, false)
+ modifyNotification(mContext).setColorized(false)
+ }
+
+ // THEN the entry is NOT in the fgs section
+ assertFalse(sectioner.isInSection(entry))
+ }
+
+ @Test
+ fun testIncludeCallInSection_importanceDefault() {
+ // GIVEN the notification represents a call with > min importance
+ val entry = buildEntry {
+ setImportance(NotificationManager.IMPORTANCE_DEFAULT)
+ modifyNotification(mContext).setStyle(makeCallStyle())
+ }
+
+ // THEN the entry is in the fgs section
+ assertTrue(sectioner.isInSection(entry))
+ }
+
+ @Test
+ fun testDiscludeCallInSection_importanceMin() {
+ // GIVEN the notification represents a call with min importance
+ val entry = buildEntry {
+ setImportance(NotificationManager.IMPORTANCE_MIN)
+ modifyNotification(mContext).setStyle(makeCallStyle())
+ }
+
+ // THEN the entry is NOT in the fgs section
+ assertFalse(sectioner.isInSection(entry))
+ }
+
+ @Test
+ @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+ fun testIncludePromotedOngoingInSection_flagEnabled() {
+ // GIVEN the notification has FLAG_PROMOTED_ONGOING
+ val entry = buildEntry { setFlag(mContext, Notification.FLAG_PROMOTED_ONGOING, true) }
+
+ // THEN the entry is in the fgs section
+ assertTrue(sectioner.isInSection(entry))
+ }
+
+ @Test
+ @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+ fun testDiscludePromotedOngoingInSection_flagDisabled() {
+ // GIVEN the notification has FLAG_PROMOTED_ONGOING
+ val entry = buildEntry { setFlag(mContext, Notification.FLAG_PROMOTED_ONGOING, true) }
+
+ // THEN the entry is NOT in the fgs section
+ assertFalse(sectioner.isInSection(entry))
+ }
+
+ @Test
+ @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+ fun promoterSelectsPromotedOngoing_flagEnabled() {
+ val promoter: NotifPromoter = withArgCaptor { verify(notifPipeline).addPromoter(capture()) }
+
+ // GIVEN the notification has FLAG_PROMOTED_ONGOING
+ val entry = buildEntry { setFlag(mContext, Notification.FLAG_PROMOTED_ONGOING, true) }
+
+ // THEN the entry is promoted to top level
+ assertTrue(promoter.shouldPromoteToTopLevel(entry))
+ }
+
+ @Test
+ @EnableFlags(PromotedNotificationUi.FLAG_NAME)
+ fun promoterIgnoresNonPromotedOngoing_flagEnabled() {
+ val promoter: NotifPromoter = withArgCaptor { verify(notifPipeline).addPromoter(capture()) }
+
+ // GIVEN the notification does not have FLAG_PROMOTED_ONGOING
+ val entry = buildEntry { setFlag(mContext, Notification.FLAG_PROMOTED_ONGOING, false) }
+
+ // THEN the entry is NOT promoted to top level
+ assertFalse(promoter.shouldPromoteToTopLevel(entry))
+ }
+
+ @Test
+ @DisableFlags(PromotedNotificationUi.FLAG_NAME)
+ fun noPromoterAdded_flagDisabled() {
+ verify(notifPipeline, never()).addPromoter(any())
+ }
+
+ @Test
+ @EnableFlags(
+ PromotedNotificationUi.FLAG_NAME,
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+ )
+ fun comparatorPutsCallBeforeOther() =
+ kosmos.runTest {
+ // GIVEN a call and a promoted ongoing notification
+ val callEntry = buildOngoingCallEntry(promoted = false)
+ val ronEntry = buildPromotedOngoingEntry()
+ val otherEntry = buildNotificationEntry(tag = "other")
+
+ kosmos.renderNotificationListInteractor.setRenderedList(
+ listOf(callEntry, ronEntry, otherEntry)
+ )
+
+ val orderedChipNotificationKeys by
+ collectLastValue(kosmos.promotedNotificationsInteractor.orderedChipNotificationKeys)
+
+ // THEN the order of the notification keys should be the call then the RON
+ assertThat(orderedChipNotificationKeys)
+ .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0")
+
+ // VERIFY that the comparator puts the call before the ron
+ assertThat(sectioner.comparator!!.compare(callEntry, ronEntry)).isLessThan(0)
+ // VERIFY that the comparator puts the ron before the other
+ assertThat(sectioner.comparator!!.compare(ronEntry, otherEntry)).isLessThan(0)
+ }
+
+ private fun makeCallStyle(): Notification.CallStyle {
+ val pendingIntent =
+ PendingIntent.getBroadcast(mContext, 0, Intent("action"), PendingIntent.FLAG_IMMUTABLE)
+ val person = Person.Builder().setName("person").build()
+ return Notification.CallStyle.forOngoingCall(person, pendingIntent)
+ }
+
+ companion object {
+ private const val NOTIF_USER_ID = 0
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
index db5921d8bd36..3dd0982ba2ff 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
@@ -17,23 +17,29 @@
package com.android.systemui.statusbar.notification.collection.render
import android.os.Build
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.assertLogsWtf
+import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import org.junit.Assume
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.never
@@ -44,6 +50,9 @@ import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
class GroupExpansionManagerTest : SysuiTestCase() {
+ @get:Rule
+ val setFlagsRule = SetFlagsRule()
+
private lateinit var underTest: GroupExpansionManagerImpl
private val dumpManager: DumpManager = mock()
@@ -52,8 +61,8 @@ class GroupExpansionManagerTest : SysuiTestCase() {
private val pipeline: NotifPipeline = mock()
private lateinit var beforeRenderListListener: OnBeforeRenderListListener
- private val summary1 = notificationEntry("foo", 1)
- private val summary2 = notificationEntry("bar", 1)
+ private val summary1 = notificationSummaryEntry("foo", 1)
+ private val summary2 = notificationSummaryEntry("bar", 1)
private val entries =
listOf<ListEntry>(
GroupEntryBuilder()
@@ -82,15 +91,25 @@ class GroupExpansionManagerTest : SysuiTestCase() {
private fun notificationEntry(pkg: String, id: Int) =
NotificationEntryBuilder().setPkg(pkg).setId(id).build().apply { row = mock() }
+ private fun notificationSummaryEntry(pkg: String, id: Int) =
+ NotificationEntryBuilder().setPkg(pkg).setId(id).setParent(GroupEntry.ROOT_ENTRY).build()
+ .apply { row = mock() }
+
@Before
fun setUp() {
whenever(groupMembershipManager.getGroupSummary(summary1)).thenReturn(summary1)
whenever(groupMembershipManager.getGroupSummary(summary2)).thenReturn(summary2)
+ whenever(groupMembershipManager.getGroupRoot(summary1.entryAdapter))
+ .thenReturn(summary1.entryAdapter)
+ whenever(groupMembershipManager.getGroupRoot(summary2.entryAdapter))
+ .thenReturn(summary2.entryAdapter)
+
underTest = GroupExpansionManagerImpl(dumpManager, groupMembershipManager)
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun notifyOnlyOnChange() {
var listenerCalledCount = 0
underTest.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
@@ -108,6 +127,25 @@ class GroupExpansionManagerTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun notifyOnlyOnChange_withEntryAdapter() {
+ var listenerCalledCount = 0
+ underTest.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
+
+ underTest.setGroupExpanded(summary1.entryAdapter, false)
+ assertThat(listenerCalledCount).isEqualTo(0)
+ underTest.setGroupExpanded(summary1.entryAdapter, true)
+ assertThat(listenerCalledCount).isEqualTo(1)
+ underTest.setGroupExpanded(summary2.entryAdapter, true)
+ assertThat(listenerCalledCount).isEqualTo(2)
+ underTest.setGroupExpanded(summary1.entryAdapter, true)
+ assertThat(listenerCalledCount).isEqualTo(2)
+ underTest.setGroupExpanded(summary2.entryAdapter, false)
+ assertThat(listenerCalledCount).isEqualTo(3)
+ }
+
+ @Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun expandUnattachedEntry() {
// First, expand the entry when it is attached.
underTest.setGroupExpanded(summary1, true)
@@ -122,6 +160,22 @@ class GroupExpansionManagerTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun expandUnattachedEntryAdapter() {
+ // First, expand the entry when it is attached.
+ underTest.setGroupExpanded(summary1.entryAdapter, true)
+ assertThat(underTest.isGroupExpanded(summary1.entryAdapter)).isTrue()
+
+ // Un-attach it, and un-expand it.
+ NotificationEntryBuilder.setNewParent(summary1, null)
+ underTest.setGroupExpanded(summary1.entryAdapter, false)
+
+ // Expanding again should throw.
+ assertLogsWtf { underTest.setGroupExpanded(summary1.entryAdapter, true) }
+ }
+
+ @Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun syncWithPipeline() {
underTest.attach(pipeline)
beforeRenderListListener = withArgCaptor {
@@ -143,4 +197,28 @@ class GroupExpansionManagerTest : SysuiTestCase() {
verify(listener).onGroupExpansionChange(summary1.row, false)
verifyNoMoreInteractions(listener)
}
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun syncWithPipeline_withEntryAdapter() {
+ underTest.attach(pipeline)
+ beforeRenderListListener = withArgCaptor {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ val listener: OnGroupExpansionChangeListener = mock()
+ underTest.registerGroupExpansionChangeListener(listener)
+
+ beforeRenderListListener.onBeforeRenderList(entries)
+ verify(listener, never()).onGroupExpansionChange(any(), any())
+
+ // Expand one of the groups.
+ underTest.setGroupExpanded(summary1.entryAdapter, true)
+ verify(listener).onGroupExpansionChange(summary1.row, true)
+
+ // Empty the pipeline list and verify that the group is no longer expanded.
+ beforeRenderListListener.onBeforeRenderList(emptyList())
+ verify(listener).onGroupExpansionChange(summary1.row, false)
+ verifyNoMoreInteractions(listener)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
index 2cbcc5a8d925..dcbf44e6e301 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
@@ -16,34 +16,46 @@
package com.android.systemui.statusbar.notification.collection.render
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class GroupMembershipManagerTest : SysuiTestCase() {
+
+ @get:Rule
+ val setFlagsRule = SetFlagsRule()
+
private var underTest = GroupMembershipManagerImpl()
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun isChildInGroup_topLevel() {
val topLevelEntry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
assertThat(underTest.isChildInGroup(topLevelEntry)).isFalse()
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun isChildInGroup_noParent() {
val noParentEntry = NotificationEntryBuilder().setParent(null).build()
assertThat(underTest.isChildInGroup(noParentEntry)).isFalse()
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun isChildInGroup_summary() {
val groupKey = "group"
val summary =
@@ -57,12 +69,14 @@ class GroupMembershipManagerTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun isGroupSummary_topLevelEntry() {
val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
assertThat(underTest.isGroupSummary(entry)).isFalse()
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun isGroupSummary_summary() {
val groupKey = "group"
val summary =
@@ -76,6 +90,7 @@ class GroupMembershipManagerTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun isGroupSummary_child() {
val groupKey = "group"
val summary =
@@ -90,12 +105,14 @@ class GroupMembershipManagerTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun getGroupSummary_topLevelEntry() {
val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
assertThat(underTest.getGroupSummary(entry)).isNull()
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun getGroupSummary_summary() {
val groupKey = "group"
val summary =
@@ -109,6 +126,7 @@ class GroupMembershipManagerTest : SysuiTestCase() {
}
@Test
+ @DisableFlags(NotificationBundleUi.FLAG_NAME)
fun getGroupSummary_child() {
val groupKey = "group"
val summary =
@@ -121,4 +139,104 @@ class GroupMembershipManagerTest : SysuiTestCase() {
assertThat(underTest.getGroupSummary(entry)).isEqualTo(summary)
}
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isChildEntryAdapterInGroup_topLevel() {
+ val topLevelEntry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
+ assertThat(underTest.isChildInGroup(topLevelEntry.entryAdapter)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isChildEntryAdapterInGroup_noParent() {
+ val noParentEntry = NotificationEntryBuilder().setParent(null).build()
+ assertThat(underTest.isChildInGroup(noParentEntry.entryAdapter)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isChildEntryAdapterInGroup_summary() {
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
+
+ assertThat(underTest.isChildInGroup(summary.entryAdapter)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isGroupRoot_topLevelEntry() {
+ val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
+ assertThat(underTest.isGroupRoot(entry.entryAdapter)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isGroupRoot_summary() {
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
+
+ assertThat(underTest.isGroupRoot(summary.entryAdapter)).isTrue()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun isGroupRoot_child() {
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build()
+
+ assertThat(underTest.isGroupRoot(entry.entryAdapter)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun getGroupRoot_topLevelEntry() {
+ val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
+ assertThat(underTest.getGroupRoot(entry.entryAdapter)).isNull()
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun getGroupRoot_summary() {
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
+
+ assertThat(underTest.getGroupRoot(summary.entryAdapter)).isEqualTo(summary.entryAdapter)
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ fun getGroupRoot_child() {
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build()
+
+ assertThat(underTest.getGroupRoot(entry.entryAdapter)).isEqualTo(summary.entryAdapter)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt
index 5ba972def76d..7cbc839c0ab5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt
@@ -140,7 +140,7 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
@Test
@EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
- @DisableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
+ @DisableFlags(Flags.FLAG_MODES_UI)
fun text_changesWhenNotifsHiddenInShade() =
testScope.runTest {
val text by collectLastValue(underTest.text)
@@ -163,7 +163,7 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
- @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
+ @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
fun text_changesWhenLocaleChanges() =
testScope.runTest {
val text by collectLastValue(underTest.text)
@@ -186,7 +186,7 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
- @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
+ @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
fun text_reflectsModesHidingNotifications() =
testScope.runTest {
val text by collectLastValue(underTest.text)
@@ -250,7 +250,7 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
- @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
+ @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
fun onClick_whenHistoryDisabled_leadsToSettingsPage() =
testScope.runTest {
val onClick by collectLastValue(underTest.onClick)
@@ -264,7 +264,7 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
- @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
+ @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
fun onClick_whenHistoryEnabled_leadsToHistoryPage() =
testScope.runTest {
val onClick by collectLastValue(underTest.onClick)
@@ -279,7 +279,7 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
- @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
+ @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
fun onClick_whenOneModeHidingNotifications_leadsToModeSettings() =
testScope.runTest {
val onClick by collectLastValue(underTest.onClick)
@@ -305,7 +305,7 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
- @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
+ @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
fun onClick_whenMultipleModesHidingNotifications_leadsToGeneralModesSettings() =
testScope.runTest {
val onClick by collectLastValue(underTest.onClick)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
index 339f8fac3820..e22acd53e584 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
@@ -106,11 +106,15 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
this.addOverride(R.integer.touch_acceptance_delay, TEST_TOUCH_ACCEPTANCE_TIME)
this.addOverride(
R.integer.heads_up_notification_minimum_time,
- TEST_MINIMUM_DISPLAY_TIME,
+ TEST_MINIMUM_DISPLAY_TIME_DEFAULT,
)
this.addOverride(
R.integer.heads_up_notification_minimum_time_with_throttling,
- TEST_MINIMUM_DISPLAY_TIME,
+ TEST_MINIMUM_DISPLAY_TIME_DEFAULT,
+ )
+ this.addOverride(
+ R.integer.heads_up_notification_minimum_time_for_user_initiated,
+ TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED,
)
this.addOverride(R.integer.heads_up_notification_decay, TEST_AUTO_DISMISS_TIME)
this.addOverride(
@@ -414,7 +418,7 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
- fun testRemoveNotification_beforeMinimumDisplayTime() {
+ fun testRemoveNotification_beforeMinimumDisplayTime_notUserInitiatedHun() {
val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
useAccessibilityTimeout(false)
@@ -429,18 +433,22 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
assertThat(removedImmediately).isFalse()
assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()
- systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong())
+ systemClock.advanceTime(
+ ((TEST_MINIMUM_DISPLAY_TIME_DEFAULT + TEST_AUTO_DISMISS_TIME) / 2).toLong()
+ )
assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
}
@Test
- fun testRemoveNotification_afterMinimumDisplayTime() {
+ fun testRemoveNotification_afterMinimumDisplayTime_notUserInitiatedHun() {
val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
useAccessibilityTimeout(false)
underTest.showNotification(entry)
- systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong())
+ systemClock.advanceTime(
+ ((TEST_MINIMUM_DISPLAY_TIME_DEFAULT + TEST_AUTO_DISMISS_TIME) / 2).toLong()
+ )
assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()
@@ -455,6 +463,57 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
}
@Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun testRemoveNotification_beforeMinimumDisplayTime_forUserInitiatedHun() {
+ useAccessibilityTimeout(false)
+
+ val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ entry.row = testHelper.createRow()
+ underTest.showNotification(entry, isPinnedByUser = true)
+
+ val removedImmediately =
+ underTest.removeNotification(
+ entry.key,
+ /* releaseImmediately = */ false,
+ "beforeMinimumDisplayTime",
+ )
+ assertThat(removedImmediately).isFalse()
+ assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()
+
+ systemClock.advanceTime(
+ ((TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED + TEST_AUTO_DISMISS_TIME) / 2).toLong()
+ )
+
+ assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
+ }
+
+ @Test
+ @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+ fun testRemoveNotification_afterMinimumDisplayTime_forUserInitiatedHun() {
+ useAccessibilityTimeout(false)
+
+ val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+ entry.row = testHelper.createRow()
+ underTest.showNotification(entry, isPinnedByUser = true)
+
+ systemClock.advanceTime(
+ ((TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED + TEST_AUTO_DISMISS_TIME) / 2).toLong()
+ )
+
+ assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue()
+
+ val removedImmediately =
+ underTest.removeNotification(
+ entry.key,
+ /* releaseImmediately = */ false,
+ "afterMinimumDisplayTime",
+ )
+
+ assertThat(removedImmediately).isTrue()
+ assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse()
+ }
+
+ @Test
fun testRemoveNotification_releaseImmediately() {
val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
@@ -1047,16 +1106,21 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() {
}
companion object {
- const val TEST_TOUCH_ACCEPTANCE_TIME = 200
- const val TEST_A11Y_AUTO_DISMISS_TIME = 1000
- const val TEST_EXTENSION_TIME = 500
+ private const val TEST_TOUCH_ACCEPTANCE_TIME = 200
+ private const val TEST_A11Y_AUTO_DISMISS_TIME = 1000
+ private const val TEST_EXTENSION_TIME = 500
- const val TEST_MINIMUM_DISPLAY_TIME = 400
- const val TEST_AUTO_DISMISS_TIME = 600
- const val TEST_STICKY_AUTO_DISMISS_TIME = 800
+ private const val TEST_MINIMUM_DISPLAY_TIME_DEFAULT = 400
+ private const val TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED = 500
+ private const val TEST_AUTO_DISMISS_TIME = 600
+ private const val TEST_STICKY_AUTO_DISMISS_TIME = 800
init {
- assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME)
+ assertThat(TEST_MINIMUM_DISPLAY_TIME_DEFAULT)
+ .isLessThan(TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED)
+ assertThat(TEST_MINIMUM_DISPLAY_TIME_DEFAULT).isLessThan(TEST_AUTO_DISMISS_TIME)
+ assertThat(TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED)
+ .isLessThan(TEST_AUTO_DISMISS_TIME)
assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME)
assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
index ee4d0990d38f..ee698ae20adb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
@@ -32,8 +32,12 @@ import com.android.systemui.statusbar.notification.data.repository.activeNotific
import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor
+import com.android.systemui.statusbar.notification.promoted.domain.interactor.aodPromotedNotificationInteractor
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style.Base
import com.android.systemui.statusbar.notification.shared.byIsAmbient
import com.android.systemui.statusbar.notification.shared.byIsLastMessageFromReply
+import com.android.systemui.statusbar.notification.shared.byIsPromoted
import com.android.systemui.statusbar.notification.shared.byIsPulsing
import com.android.systemui.statusbar.notification.shared.byIsRowDismissed
import com.android.systemui.statusbar.notification.shared.byIsSilent
@@ -58,12 +62,14 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
private val testScope = kosmos.testScope
private val activeNotificationListRepository = kosmos.activeNotificationListRepository
private val notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor
+ private val aodPromotedNotificationInteractor = kosmos.aodPromotedNotificationInteractor
private val underTest =
NotificationIconsInteractor(
kosmos.activeNotificationsInteractor,
kosmos.bubblesOptional,
kosmos.headsUpNotificationIconInteractor,
+ kosmos.aodPromotedNotificationInteractor,
kosmos.notificationsKeyguardViewStateRepository,
)
@@ -141,6 +147,22 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
}
+
+ @Test
+ fun filteredEntrySet_showAodPromoted() {
+ testScope.runTest {
+ val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = true))
+ assertThat(filteredSet).comparingElementsUsing(byIsPromoted).contains(true)
+ }
+ }
+
+ @Test
+ fun filteredEntrySet_noAodPromoted() {
+ testScope.runTest {
+ val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = false))
+ assertThat(filteredSet).comparingElementsUsing(byIsPromoted).doesNotContain(true)
+ }
+ }
}
@SmallTest
@@ -326,4 +348,12 @@ private val testIcons =
activeNotificationModel(key = "notif5", isLastMessageFromReply = true),
activeNotificationModel(key = "notif6", isSuppressedFromStatusBar = true),
activeNotificationModel(key = "notif7", isPulsing = true),
+ activeNotificationModel(key = "notif8", promotedContent = promotedContent("notif8", Base)),
)
+
+private fun promotedContent(
+ key: String,
+ style: PromotedNotificationContentModel.Style,
+): PromotedNotificationContentModel {
+ return PromotedNotificationContentModel.Builder(key).apply { this.style = style }.build()
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierTest.kt
new file mode 100644
index 000000000000..75f5de0118d4
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.people
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.content.pm.ShortcutInfo
+import android.service.notification.NotificationListenerService.Ranking
+import android.service.notification.StatusBarNotification
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.RankingBuilder
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.Mockito.mock
+
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PeopleNotificationIdentifierTest : SysuiTestCase() {
+
+ private lateinit var underTest: PeopleNotificationIdentifierImpl
+
+ private val summary1 = notificationEntry("foo", 1, summary = true)
+ private val summary2 = notificationEntry("bar", 1, summary = true)
+ private val entries =
+ listOf<GroupEntry>(
+ GroupEntryBuilder()
+ .setSummary(summary1)
+ .setChildren(
+ listOf(
+ notificationEntry("foo", 2),
+ notificationEntry("foo", 3),
+ notificationEntry("foo", 4)
+ )
+ )
+ .build(),
+ GroupEntryBuilder()
+ .setSummary(summary2)
+ .setChildren(
+ listOf(
+ notificationEntry("bar", 2),
+ notificationEntry("bar", 3),
+ notificationEntry("bar", 4)
+ )
+ )
+ .build()
+ )
+
+ private fun notificationEntry(
+ pkg: String,
+ id: Int,
+ summary: Boolean = false
+ ): NotificationEntry {
+ val sbn = mock(StatusBarNotification::class.java)
+ Mockito.`when`(sbn.key).thenReturn("key")
+ Mockito.`when`(sbn.notification).thenReturn(mock(Notification::class.java))
+ if (summary)
+ Mockito.`when`(sbn.notification.isGroupSummary).thenReturn(true)
+ return NotificationEntryBuilder().setPkg(pkg)
+ .setId(id)
+ .setSbn(sbn)
+ .build().apply {
+ row = mock(ExpandableNotificationRow::class.java)
+ }
+ }
+
+ private fun personRanking(entry: NotificationEntry, personType: Int): Ranking {
+ val channel = NotificationChannel("person", "person", 4)
+ channel.setConversationId("parent", "person")
+ channel.setImportantConversation(true)
+
+ val br = RankingBuilder(entry.ranking)
+
+ when (personType) {
+ TYPE_NON_PERSON -> br.setIsConversation(false)
+ TYPE_PERSON -> {
+ br.setIsConversation(true)
+ br.setShortcutInfo(null)
+ }
+
+ TYPE_IMPORTANT_PERSON -> {
+ br.setIsConversation(true)
+ br.setShortcutInfo(mock(ShortcutInfo::class.java))
+ br.setChannel(channel)
+ }
+
+ else -> {
+ br.setIsConversation(true)
+ br.setShortcutInfo(mock(ShortcutInfo::class.java))
+ }
+ }
+
+ return br.build()
+ }
+
+ @Before
+ fun setUp() {
+ val personExtractor = object : NotificationPersonExtractor {
+ public override fun isPersonNotification(sbn: StatusBarNotification): Boolean {
+ return true
+ }
+ }
+
+ underTest = PeopleNotificationIdentifierImpl(
+ personExtractor,
+ GroupMembershipManagerImpl()
+ )
+ }
+
+ private val Ranking.personTypeInfo
+ get() = when {
+ !isConversation -> TYPE_NON_PERSON
+ conversationShortcutInfo == null -> TYPE_PERSON
+ channel?.isImportantConversation == true -> TYPE_IMPORTANT_PERSON
+ else -> TYPE_FULL_PERSON
+ }
+
+ @Test
+ fun getPeopleNotificationType_entryIsImportant() {
+ summary1.setRanking(personRanking(summary1, TYPE_IMPORTANT_PERSON))
+
+ assertThat(underTest.getPeopleNotificationType(summary1)).isEqualTo(TYPE_IMPORTANT_PERSON)
+ }
+
+ @Test
+ fun getPeopleNotificationType_importantChild() {
+ entries.get(0).getChildren().get(0).setRanking(
+ personRanking(entries.get(0).getChildren().get(0), TYPE_IMPORTANT_PERSON)
+ )
+
+ assertThat(entries.get(0).summary?.let { underTest.getPeopleNotificationType(it) })
+ .isEqualTo(TYPE_IMPORTANT_PERSON)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt
new file mode 100644
index 000000000000..aa6e76d08c17
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.promoted.domain.interactor
+
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
+import com.android.systemui.statusbar.core.StatusBarRootModernization
+import com.android.systemui.statusbar.notification.buildNotificationEntry
+import com.android.systemui.statusbar.notification.buildOngoingCallEntry
+import com.android.systemui.statusbar.notification.buildPromotedOngoingEntry
+import com.android.systemui.statusbar.notification.domain.interactor.renderNotificationListInteractor
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableFlags(
+ PromotedNotificationUi.FLAG_NAME,
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+)
+class PromotedNotificationsInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+
+ private val Kosmos.underTest by Fixture { promotedNotificationsInteractor }
+
+ @Before
+ fun setUp() {
+ kosmos.statusBarNotificationChipsInteractor.start()
+ }
+
+ @Test
+ fun orderedChipNotificationKeys_containsNonPromotedCalls() =
+ kosmos.runTest {
+ // GIVEN a call and a promoted ongoing notification
+ val callEntry = buildOngoingCallEntry(promoted = false)
+ val ronEntry = buildPromotedOngoingEntry()
+ val otherEntry = buildNotificationEntry(tag = "other")
+
+ renderNotificationListInteractor.setRenderedList(
+ listOf(callEntry, ronEntry, otherEntry)
+ )
+
+ val orderedChipNotificationKeys by
+ collectLastValue(underTest.orderedChipNotificationKeys)
+
+ // THEN the order of the notification keys should be the call then the RON
+ assertThat(orderedChipNotificationKeys)
+ .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0")
+ }
+
+ @Test
+ fun orderedChipNotificationKeys_containsPromotedCalls() =
+ kosmos.runTest {
+ // GIVEN a call and a promoted ongoing notification
+ val callEntry = buildOngoingCallEntry(promoted = true)
+ val ronEntry = buildPromotedOngoingEntry()
+ val otherEntry = buildNotificationEntry(tag = "other")
+
+ renderNotificationListInteractor.setRenderedList(
+ listOf(callEntry, ronEntry, otherEntry)
+ )
+
+ val orderedChipNotificationKeys by
+ collectLastValue(underTest.orderedChipNotificationKeys)
+
+ // THEN the order of the notification keys should be the call then the RON
+ assertThat(orderedChipNotificationKeys)
+ .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0")
+ }
+
+ @Test
+ fun topPromotedNotificationContent_skipsNonPromotedCalls() =
+ kosmos.runTest {
+ // GIVEN a non-promoted call and a promoted ongoing notification
+ val callEntry = buildOngoingCallEntry(promoted = false)
+ val ronEntry = buildPromotedOngoingEntry()
+ val otherEntry = buildNotificationEntry(tag = "other")
+
+ renderNotificationListInteractor.setRenderedList(
+ listOf(callEntry, ronEntry, otherEntry)
+ )
+
+ val topPromotedNotificationContent by
+ collectLastValue(underTest.topPromotedNotificationContent)
+
+ // THEN the ron is first because the call has no content
+ assertThat(topPromotedNotificationContent?.identity?.key)
+ .isEqualTo("0|test_pkg|0|ron|0")
+ }
+
+ @Test
+ fun topPromotedNotificationContent_includesPromotedCalls() =
+ kosmos.runTest {
+ // GIVEN a promoted call and a promoted ongoing notification
+ val callEntry = buildOngoingCallEntry(promoted = true)
+ val ronEntry = buildPromotedOngoingEntry()
+ val otherEntry = buildNotificationEntry(tag = "other")
+
+ renderNotificationListInteractor.setRenderedList(
+ listOf(callEntry, ronEntry, otherEntry)
+ )
+
+ val topPromotedNotificationContent by
+ collectLastValue(underTest.topPromotedNotificationContent)
+
+ // THEN the call is the top notification
+ assertThat(topPromotedNotificationContent?.identity?.key)
+ .isEqualTo("0|test_pkg|0|call|0")
+ }
+
+ @Test
+ fun topPromotedNotificationContent_nullWithNoPromotedNotifications() =
+ kosmos.runTest {
+ // GIVEN a a non-promoted call and no promoted ongoing entry
+ val callEntry = buildOngoingCallEntry(promoted = false)
+ val otherEntry = buildNotificationEntry(tag = "other")
+
+ renderNotificationListInteractor.setRenderedList(listOf(callEntry, otherEntry))
+
+ val topPromotedNotificationContent by
+ collectLastValue(underTest.topPromotedNotificationContent)
+
+ // THEN there is no top promoted notification
+ assertThat(topPromotedNotificationContent).isNull()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 7d406b4b397c..9f35d631bd45 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -67,6 +67,7 @@ import com.android.systemui.media.controls.util.MediaFeatureFlag;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.promoted.FakePromotedNotificationContentExtractor;
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
@@ -248,14 +249,13 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
true /* isNewView */, (v, p, r) -> true,
new InflationCallback() {
@Override
- public void handleInflationException(NotificationEntry entry,
- Exception e) {
+ public void handleInflationException(Exception e) {
countDownLatch.countDown();
throw new RuntimeException("No Exception expected");
}
@Override
- public void onAsyncInflationFinished(NotificationEntry entry) {
+ public void onAsyncInflationFinished() {
countDownLatch.countDown();
}
}, mRow.getPrivateLayout(), null, null, new HashMap<>(),
@@ -539,8 +539,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
inflater.setInflateSynchronously(true);
InflationCallback callback = new InflationCallback() {
@Override
- public void handleInflationException(NotificationEntry entry,
- Exception e) {
+ public void handleInflationException(Exception e) {
if (!expectingException) {
exceptionHolder.setException(e);
}
@@ -548,7 +547,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
}
@Override
- public void onAsyncInflationFinished(NotificationEntry entry) {
+ public void onAsyncInflationFinished() {
if (expectingException) {
exceptionHolder.setException(new RuntimeException(
"Inflation finished even though there should be an error"));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
index d43cc78e20dc..4c1f4f17e00c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
@@ -71,6 +71,10 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.icon.AppIconProvider
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
+import com.android.systemui.statusbar.notification.row.icon.appIconProvider
+import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.testKosmos
@@ -203,6 +207,8 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
accessibilityManager,
highPriorityProvider,
iNotificationManager,
+ kosmos.appIconProvider,
+ kosmos.notificationIconStyleProvider,
userManager,
peopleSpaceWidgetManager,
launcherApps,
@@ -512,6 +518,8 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
.bindNotification(
any<PackageManager>(),
any<INotificationManager>(),
+ any<AppIconProvider>(),
+ any<NotificationIconStyleProvider>(),
eq(onUserInteractionCallback),
eq(channelEditorDialogController),
eq(statusBarNotification.packageName),
@@ -550,6 +558,8 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
.bindNotification(
any<PackageManager>(),
any<INotificationManager>(),
+ any<AppIconProvider>(),
+ any<NotificationIconStyleProvider>(),
eq(onUserInteractionCallback),
eq(channelEditorDialogController),
eq(statusBarNotification.packageName),
@@ -586,6 +596,8 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase(
.bindNotification(
any<PackageManager>(),
any<INotificationManager>(),
+ any<AppIconProvider>(),
+ any<NotificationIconStyleProvider>(),
eq(onUserInteractionCallback),
eq(channelEditorDialogController),
eq(statusBarNotification.packageName),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt
index 2945fa98caad..96ae07035ed2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.kt
@@ -64,6 +64,10 @@ import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.notification.AssistantFeedbackController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.row.icon.AppIconProvider
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
+import com.android.systemui.statusbar.notification.row.icon.appIconProvider
+import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
import com.android.telecom.telecomManager
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.CountDownLatch
@@ -862,6 +866,8 @@ class NotificationInfoTest : SysuiTestCase() {
private fun bindNotification(
pm: PackageManager = this.mockPackageManager,
iNotificationManager: INotificationManager = this.mockINotificationManager,
+ appIconProvider: AppIconProvider = kosmos.appIconProvider,
+ iconStyleProvider: NotificationIconStyleProvider = kosmos.notificationIconStyleProvider,
onUserInteractionCallback: OnUserInteractionCallback = this.onUserInteractionCallback,
channelEditorDialogController: ChannelEditorDialogController =
this.channelEditorDialogController,
@@ -882,6 +888,8 @@ class NotificationInfoTest : SysuiTestCase() {
underTest.bindNotification(
pm,
iNotificationManager,
+ appIconProvider,
+ iconStyleProvider,
onUserInteractionCallback,
channelEditorDialogController,
pkg,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
index 82eca3735a71..ce3aee1d88d2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTIO
import com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.promoted.FakePromotedNotificationContentExtractor
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
@@ -223,12 +224,12 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() {
remoteViewClickHandler = { _, _, _ -> true },
callback =
object : InflationCallback {
- override fun handleInflationException(entry: NotificationEntry, e: Exception) {
+ override fun handleInflationException(e: Exception) {
countDownLatch.countDown()
throw RuntimeException("No Exception expected")
}
- override fun onAsyncInflationFinished(entry: NotificationEntry) {
+ override fun onAsyncInflationFinished() {
countDownLatch.countDown()
}
},
@@ -675,14 +676,14 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() {
inflater.setInflateSynchronously(true)
val callback: InflationCallback =
object : InflationCallback {
- override fun handleInflationException(entry: NotificationEntry, e: Exception) {
+ override fun handleInflationException(e: Exception) {
if (!expectingException) {
exceptionHolder.exception = e
}
countDownLatch.countDown()
}
- override fun onAsyncInflationFinished(entry: NotificationEntry) {
+ override fun onAsyncInflationFinished() {
if (expectingException) {
exceptionHolder.exception =
RuntimeException(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index c39b252cd795..f2131da8f0bb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -615,7 +615,7 @@ public class NotificationTestHelper {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
inflater.setFactory2(new RowInflaterTask.RowAsyncLayoutInflater(entry, mSystemClock,
- mRowInflaterTaskLogger));
+ mRowInflaterTaskLogger, UserHandle.of(entry.getSbn().getNormalizedUserId())));
mRow = (ExpandableNotificationRow) inflater.inflate(
R.layout.status_bar_notification_row,
null /* root */,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java
index acdbd6237733..5638e0b434aa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfoTest.java
@@ -48,6 +48,8 @@ import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
import org.junit.Before;
import org.junit.Rule;
@@ -57,8 +59,6 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.concurrent.CountDownLatch;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@@ -82,6 +82,10 @@ public class PromotedNotificationInfoTest extends SysuiTestCase {
@Mock
private INotificationManager mMockINotificationManager;
@Mock
+ private AppIconProvider mMockAppIconProvider;
+ @Mock
+ private NotificationIconStyleProvider mMockIconStyleProvider;
+ @Mock
private PackageManager mMockPackageManager;
@Mock
private OnUserInteractionCallback mOnUserInteractionCallback;
@@ -127,10 +131,11 @@ public class PromotedNotificationInfoTest extends SysuiTestCase {
public void testBindNotification_setsOnClickListenerForFeedback() throws Exception {
// Bind the notification to the Info object
- final CountDownLatch latch = new CountDownLatch(1);
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
+ mMockAppIconProvider,
+ mMockIconStyleProvider,
mOnUserInteractionCallback,
mChannelEditorDialogController,
TEST_PACKAGE_NAME,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
index 16c5c8a98253..531b30b9547a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
@@ -33,7 +33,12 @@ val byIsRowDismissed: Correspondence<ActiveNotificationModel, Boolean> =
val byIsLastMessageFromReply: Correspondence<ActiveNotificationModel, Boolean> =
Correspondence.transforming(
{ it?.isLastMessageFromReply },
- "has an isLastMessageFromReply value of"
+ "has an isLastMessageFromReply value of",
)
val byIsPulsing: Correspondence<ActiveNotificationModel, Boolean> =
Correspondence.transforming({ it?.isPulsing }, "has an isPulsing value of")
+val byIsPromoted: Correspondence<ActiveNotificationModel, Boolean> =
+ Correspondence.transforming(
+ { it?.promotedContent != null },
+ "has (or doesn't have) a promoted content model",
+ )
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 256da253588c..9c5d65ec12ec 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.statusbar.notification.stack
+import android.os.UserHandle
import android.platform.test.annotations.EnableFlags
import android.service.notification.StatusBarNotification
import android.testing.TestableLooper.RunWithLooper
@@ -21,6 +22,7 @@ import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.statusbar.notification.shared.NotificationMinimalism
import com.android.systemui.statusbar.notification.shelf.NotificationShelfIconContainer
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.StackScrollAlgorithmState
@@ -978,7 +980,10 @@ open class NotificationShelfTest : SysuiTestCase() {
) {
val sbnMock: StatusBarNotification = mock()
val mockEntry = mock<NotificationEntry>().apply { whenever(this.sbn).thenReturn(sbnMock) }
- val row = ExpandableNotificationRow(mContext, null, mockEntry)
+ val row = when (NotificationBundleUi.isEnabled) {
+ true -> ExpandableNotificationRow(mContext, null, UserHandle.CURRENT)
+ false -> ExpandableNotificationRow(mContext, null, mockEntry)
+ }
whenever(ambientState.lastVisibleBackgroundChild).thenReturn(row)
whenever(ambientState.isExpansionChanging).thenReturn(true)
whenever(ambientState.expansionFraction).thenReturn(expansionFraction)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 8ec17dadcfe7..345ddae42798 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -46,9 +46,11 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry.NotifEntryAdapter;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationContentView;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -133,9 +135,11 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class);
final NotificationContentView privateLayout = mock(NotificationContentView.class);
final NotificationEntry enrEntry = mock(NotificationEntry.class);
+ final NotifEntryAdapter enrEntryAdapter = mock(NotifEntryAdapter.class);
when(enr.getPrivateLayout()).thenReturn(privateLayout);
when(enr.getEntry()).thenReturn(enrEntry);
+ when(enr.getEntryAdapter()).thenReturn(enrEntryAdapter);
when(enr.isChildInGroup()).thenReturn(true);
when(enr.areChildrenExpanded()).thenReturn(false);
@@ -144,7 +148,11 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
enr, mock(View.class), false, onExpandedVisibleRunner);
// THEN
- verify(mGroupExpansionManager).toggleGroupExpansion(enrEntry);
+ if (NotificationBundleUi.isEnabled()) {
+ verify(mGroupExpansionManager).toggleGroupExpansion(enrEntryAdapter);
+ } else {
+ verify(mGroupExpansionManager).toggleGroupExpansion(enrEntry);
+ }
verify(enr).setUserExpanded(true);
verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
}
@@ -169,7 +177,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
enr, mock(View.class), false, onExpandedVisibleRunner);
// THEN
- verify(mGroupExpansionManager, never()).toggleGroupExpansion(any());
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
verify(enr).setUserExpanded(true);
verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
}
@@ -193,7 +202,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
enr, mock(View.class), false, onExpandedVisibleRunner);
// THEN
- verify(mGroupExpansionManager, never()).toggleGroupExpansion(any());
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
verify(enr).setUserExpanded(true);
verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
}
@@ -207,9 +217,11 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class);
final NotificationContentView privateLayout = mock(NotificationContentView.class);
final NotificationEntry enrEntry = mock(NotificationEntry.class);
+ final NotifEntryAdapter enrEntryAdapter = mock(NotifEntryAdapter.class);
when(enr.getPrivateLayout()).thenReturn(privateLayout);
when(enr.getEntry()).thenReturn(enrEntry);
+ when(enr.getEntryAdapter()).thenReturn(enrEntryAdapter);
when(enr.isChildInGroup()).thenReturn(true);
when(enr.areChildrenExpanded()).thenReturn(false);
@@ -218,7 +230,11 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
enr, mock(View.class), false, onExpandedVisibleRunner);
// THEN
- verify(mGroupExpansionManager).toggleGroupExpansion(enrEntry);
+ if (NotificationBundleUi.isEnabled()) {
+ verify(mGroupExpansionManager).toggleGroupExpansion(enrEntryAdapter);
+ } else {
+ verify(mGroupExpansionManager).toggleGroupExpansion(enrEntry);
+ }
verify(enr, never()).setUserExpanded(anyBoolean());
verify(privateLayout, never()).setOnExpandedVisibleListener(any());
}
@@ -244,6 +260,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
// THEN
verify(mGroupExpansionManager, never()).toggleGroupExpansion(enrEntry);
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
verify(enr, never()).setUserExpanded(anyBoolean());
verify(privateLayout, never()).setOnExpandedVisibleListener(any());
}
@@ -272,7 +289,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
verify(enr).toggleExpansionState();
verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
verify(enr, never()).setUserExpanded(anyBoolean());
- verify(mGroupExpansionManager, never()).toggleGroupExpansion(any());
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
}
@Test
@@ -299,7 +317,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
verify(enr, never()).toggleExpansionState();
verify(privateLayout, never()).setOnExpandedVisibleListener(onExpandedVisibleRunner);
verify(enr, never()).setUserExpanded(anyBoolean());
- verify(mGroupExpansionManager, never()).toggleGroupExpansion(any());
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
}
@Test
@@ -326,7 +345,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
verify(enr).toggleExpansionState();
verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
verify(enr, never()).setUserExpanded(anyBoolean());
- verify(mGroupExpansionManager, never()).toggleGroupExpansion(any());
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
}
@Test
@@ -353,6 +373,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
verify(enr, never()).toggleExpansionState();
verify(privateLayout, never()).setOnExpandedVisibleListener(onExpandedVisibleRunner);
verify(enr, never()).setUserExpanded(anyBoolean());
- verify(mGroupExpansionManager, never()).toggleGroupExpansion(any());
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
+ verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
index 183cd8f1ae8b..eb961bd5f4ae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
@@ -57,7 +57,7 @@ class FakeHomeStatusBarViewModel(
override val ongoingActivityChipsLegacy =
MutableStateFlow(MultipleOngoingActivityChipsModelLegacy())
- override val statusBarPopupChips = MutableStateFlow(emptyList<PopupChipModel.Shown>())
+ override val popupChips = emptyList<PopupChipModel.Shown>()
override val mediaProjectionStopDialogDueToCallEndedState =
MutableStateFlow(MediaProjectionStopDialogModel.Hidden)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
index ff1ffccfb2de..22e28d883c97 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
@@ -469,7 +469,7 @@ class ZenModeInteractorTest : SysuiTestCase() {
}
@Test
- @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
+ @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI)
fun modesHidingNotifications_onlyIncludesModesWithNotifListSuppression() =
kosmos.runTest {
val modesHidingNotifications by collectLastValue(underTest.modesHidingNotifications)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColorRule.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColorRule.java
new file mode 100644
index 000000000000..ecd04a47b8ae
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColorRule.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.theme;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+
+public class HardwareColorRule implements TestRule {
+ public String color = "";
+ public String[] options = {};
+ public boolean isTesting = false;
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ HardwareColors hardwareColors = description.getAnnotation(HardwareColors.class);
+ if (hardwareColors != null) {
+ color = hardwareColors.color();
+ options = hardwareColors.options();
+ isTesting = true;
+ }
+ return base;
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColors.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColors.java
new file mode 100644
index 000000000000..0b8df2e2670e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColors.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.theme;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface HardwareColors {
+ String color();
+ String[] options();
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 5cd0846ded7e..9a0b8125fb25 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -64,6 +64,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.monet.DynamicColors;
@@ -77,6 +78,7 @@ import com.android.systemui.util.settings.SecureSettings;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -98,6 +100,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
private static final UserHandle MANAGED_USER_HANDLE = UserHandle.of(100);
private static final UserHandle PRIVATE_USER_HANDLE = UserHandle.of(101);
+ @Rule
+ public HardwareColorRule rule = new HardwareColorRule();
+
@Mock
private JavaAdapter mJavaAdapter;
@Mock
@@ -148,13 +153,17 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
@Captor
private ArgumentCaptor<ContentObserver> mSettingsObserver;
+ @Mock
+ private SystemPropertiesHelper mSystemProperties;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+
when(mFeatureFlags.isEnabled(Flags.MONET)).thenReturn(true);
when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
when(mUiModeManager.getContrast()).thenReturn(0.5f);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
+
when(mResources.getColor(eq(android.R.color.system_accent1_500), any()))
.thenReturn(Color.RED);
when(mResources.getColor(eq(android.R.color.system_accent2_500), any()))
@@ -166,11 +175,20 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
when(mResources.getColor(eq(android.R.color.system_neutral2_500), any()))
.thenReturn(Color.BLACK);
+ when(mResources.getStringArray(com.android.internal.R.array.theming_defaults))
+ .thenReturn(rule.options);
+
+ // should fallback to `*|TONAL_SPOT|home_wallpaper`
+ when(mSystemProperties.get("ro.boot.hardware.color")).thenReturn(rule.color);
+ // will try set hardware colors as boot ONLY if user is not set yet
+ when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(!rule.isTesting);
+
mThemeOverlayController = new ThemeOverlayController(mContext,
mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
- mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager) {
+ mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager,
+ mSystemProperties) {
@VisibleForTesting
protected boolean isNightMode() {
return false;
@@ -214,11 +232,58 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
public void start_checksWallpaper() {
ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class);
verify(mBgExecutor).execute(registrationRunnable.capture());
+ registrationRunnable.getValue().run();
+ verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM));
+ }
+
+ @Test
+ @HardwareColors(color = "BLK", options = {
+ "BLK|MONOCHROMATIC|#FF0000",
+ "*|VIBRANT|home_wallpaper"
+ })
+ @EnableFlags(com.android.systemui.Flags.FLAG_HARDWARE_COLOR_STYLES)
+ public void start_checkHardwareColor() {
+ // getWallpaperColors should not be called
+ ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class);
+ verify(mMainExecutor).execute(registrationRunnable.capture());
+ registrationRunnable.getValue().run();
+ verify(mWallpaperManager, never()).getWallpaperColors(anyInt());
+
+ assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(Style.MONOCHROMATIC);
+ assertThat(mThemeOverlayController.mCurrentColors.get(0).getMainColors().get(
+ 0).toArgb()).isEqualTo(Color.RED);
+ }
+
+ @Test
+ @HardwareColors(color = "", options = {
+ "BLK|MONOCHROMATIC|#FF0000",
+ "*|VIBRANT|home_wallpaper"
+ })
+ @EnableFlags(com.android.systemui.Flags.FLAG_HARDWARE_COLOR_STYLES)
+ public void start_wildcardColor() {
+ // getWallpaperColors will be called because we srt wildcard to `home_wallpaper`
+ ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class);
+ verify(mMainExecutor).execute(registrationRunnable.capture());
+ registrationRunnable.getValue().run();
+ verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM));
+ assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(Style.VIBRANT);
+ }
+
+ @Test
+ @HardwareColors(color = "NONEXISTENT", options = {})
+ @EnableFlags(com.android.systemui.Flags.FLAG_HARDWARE_COLOR_STYLES)
+ public void start_fallbackColor() {
+ // getWallpaperColors will be called because we default color source is `home_wallpaper`
+ ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class);
+ verify(mMainExecutor).execute(registrationRunnable.capture());
registrationRunnable.getValue().run();
verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM));
+
+ assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(Style.TONAL_SPOT);
}
+
@Test
public void onWallpaperColorsChanged_setsTheme_whenForeground() {
// Should ask for a new theme when wallpaper colors change
@@ -287,9 +352,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.system_palette\":\"override.package.name\","
- + "\"android.theme.customization.color_source\":\"preset\"}";
+ String jsonString = createJsonString(TestColorSource.preset, "override.package.name",
+ "TONAL_SPOT");
+
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
@@ -313,11 +378,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -348,11 +409,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -381,11 +438,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"lock_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.lock_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
@@ -404,11 +457,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"lock_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.lock_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
@@ -455,8 +504,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
@Test
public void onSettingChanged_invalidStyle() {
when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true);
- String jsonString = "{\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.theme_style\":\"some_invalid_name\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper, "A16B00",
+ "some_invalid_name");
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -473,11 +522,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -506,11 +551,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
@@ -537,11 +578,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
@@ -570,11 +607,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -599,7 +632,6 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
}
-
@Test
@EnableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI)
public void onWallpaperColorsChanged_homeWallpaperWithSameColor_shouldKeepThemeAndReapply() {
@@ -608,11 +640,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(0xffa16b00), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -642,11 +670,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -676,11 +700,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -711,11 +731,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(0xffa16b00), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -745,11 +761,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.color_source\":\"home_wallpaper\","
- + "\"android.theme.customization.system_palette\":\"A16B00\","
- + "\"android.theme.customization.accent_color\":\"A16B00\","
- + "\"android.theme.customization.color_index\":\"2\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper);
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
@@ -886,7 +898,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
- mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager) {
+ mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager,
+ mSystemProperties) {
@VisibleForTesting
protected boolean isNightMode() {
return false;
@@ -926,7 +939,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle,
- mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager) {
+ mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager,
+ mSystemProperties) {
@VisibleForTesting
protected boolean isNightMode() {
return false;
@@ -992,7 +1006,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
clearInvocations(mThemeOverlayApplier);
// Device went to sleep and second set of colors was applied.
- mainColors = new WallpaperColors(Color.valueOf(Color.BLUE),
+ mainColors = new WallpaperColors(Color.valueOf(Color.BLUE),
Color.valueOf(Color.RED), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
USER_SYSTEM);
@@ -1018,7 +1032,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
clearInvocations(mThemeOverlayApplier);
// Device went to sleep and second set of colors was applied.
- mainColors = new WallpaperColors(Color.valueOf(Color.BLUE),
+ mainColors = new WallpaperColors(Color.valueOf(Color.BLUE),
Color.valueOf(Color.RED), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
USER_SYSTEM);
@@ -1034,8 +1048,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- String jsonString =
- "{\"android.theme.customization.system_palette\":\"00FF00\"}";
+ String jsonString = createJsonString(TestColorSource.home_wallpaper, "00FF00",
+ "TONAL_SPOT");
+
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
@@ -1115,4 +1130,25 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
+ DynamicColors.getCustomColorsMapped(false).size() * 2)
).setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null));
}
+
+ private enum TestColorSource {
+ preset,
+ home_wallpaper,
+ lock_wallpaper
+ }
+
+ private String createJsonString(TestColorSource colorSource, String seedColorHex,
+ String style) {
+ return "{\"android.theme.customization.color_source\":\"" + colorSource.toString() + "\","
+ + "\"android.theme.customization.system_palette\":\"" + seedColorHex + "\","
+ + "\"android.theme.customization.accent_color\":\"" + seedColorHex + "\","
+ + "\"android.theme.customization.color_index\":\"2\","
+ + "\"android.theme.customization.theme_style\":\"" + style + "\"}";
+ }
+
+ private String createJsonString(TestColorSource colorSource) {
+ return createJsonString(colorSource, "A16B00", "TONAL_SPOT");
+ }
+
+
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt
index e484d8090c64..04ab98889755 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelTest.kt
@@ -19,21 +19,17 @@ package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
import android.bluetooth.BluetoothDevice
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.internal.logging.uiEventLogger
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
-import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.android.systemui.volume.data.repository.audioSharingRepository
-import com.android.systemui.volume.domain.interactor.audioSharingInteractor
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
@@ -43,47 +39,30 @@ import org.mockito.kotlin.mock
class AudioSharingStreamSliderViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
- private val testScope = kosmos.testScope
- private lateinit var stream: AudioSharingStreamSliderViewModel
-
- @Before
- fun setUp() {
- stream = audioSharingStreamSliderViewModel()
- }
-
- private fun audioSharingStreamSliderViewModel(): AudioSharingStreamSliderViewModel {
- return AudioSharingStreamSliderViewModel(
- testScope.backgroundScope,
- context,
- kosmos.audioSharingInteractor,
- kosmos.uiEventLogger,
- kosmos.sliderHapticsViewModelFactory,
- )
- }
+ private val underTest: AudioSharingStreamSliderViewModel =
+ with(kosmos) { audioSharingStreamSliderViewModelFactory.create(applicationCoroutineScope) }
@Test
fun slider_media_inAudioSharing() =
- with(kosmos) {
- testScope.runTest {
- val audioSharingSlider by collectLastValue(stream.slider)
+ kosmos.runTest {
+ val audioSharingSlider by collectLastValue(underTest.slider)
- val bluetoothDevice: BluetoothDevice = mock {}
- val cachedDevice: CachedBluetoothDevice = mock {
- on { groupId }.thenReturn(123)
- on { device }.thenReturn(bluetoothDevice)
- on { name }.thenReturn("my headset 2")
- }
- audioSharingRepository.setSecondaryDevice(cachedDevice)
+ val bluetoothDevice: BluetoothDevice = mock {}
+ val cachedDevice: CachedBluetoothDevice = mock {
+ on { groupId }.thenReturn(123)
+ on { device }.thenReturn(bluetoothDevice)
+ on { name }.thenReturn("my headset 2")
+ }
+ audioSharingRepository.setSecondaryDevice(cachedDevice)
- audioSharingRepository.setInAudioSharing(true)
- audioSharingRepository.setSecondaryGroupId(123)
+ audioSharingRepository.setInAudioSharing(true)
+ audioSharingRepository.setSecondaryGroupId(123)
- runCurrent()
+ runCurrent()
- assertThat(audioSharingSlider!!.label).isEqualTo("my headset 2")
- assertThat(audioSharingSlider!!.icon)
- .isEqualTo(Icon.Resource(R.drawable.ic_volume_media_bt, null))
- }
+ assertThat(audioSharingSlider!!.label).isEqualTo("my headset 2")
+ assertThat(audioSharingSlider!!.icon)
+ .isEqualTo(Icon.Resource(R.drawable.ic_volume_media_bt, null))
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
index d89516dea622..cc6a7b93eef3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
@@ -22,70 +22,69 @@ import android.content.ComponentName
import android.content.Intent
import android.content.pm.UserInfo
import android.platform.test.annotations.EnableFlags
+import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.app.wallpaperManager
import com.android.internal.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R as SysUIR
import com.android.systemui.shared.Flags as SharedFlags
+import com.android.systemui.testKosmos
import com.android.systemui.user.data.model.SelectedUserModel
import com.android.systemui.user.data.model.SelectionStatus
-import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
class WallpaperRepositoryImplTest : SysuiTestCase() {
+ private var isWallpaperSupported = true
+ private val kosmos =
+ testKosmos().apply {
+ wallpaperManager =
+ mock<WallpaperManager>() {
+ on { isWallpaperSupported } doAnswer { isWallpaperSupported }
+ }
+ }
+ private val secureSettings = kosmos.fakeSettings
+ private val testScope = kosmos.testScope
+ private val userRepository = kosmos.fakeUserRepository
+ private val broadcastDispatcher = kosmos.broadcastDispatcher
- private val testDispatcher = StandardTestDispatcher()
- private val testScope = TestScope(testDispatcher)
- private val userRepository = FakeUserRepository()
- private val wallpaperFocalAreaRepository = FakeWallpaperFocalAreaRepository()
- private val wallpaperManager: WallpaperManager = mock()
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor = mock()
-
- private val underTest: WallpaperRepositoryImpl by lazy {
- WallpaperRepositoryImpl(
- testScope.backgroundScope,
- testDispatcher,
- fakeBroadcastDispatcher,
- userRepository,
- wallpaperFocalAreaRepository,
- wallpaperManager,
- context,
- keyguardTransitionInteractor,
- )
- }
+ // Initialized in each test since certain flows rely on mocked data that isn't
+ // modifiable after start, like wallpaperManager.isWallpaperSupported
+ private lateinit var underTest: WallpaperRepositoryImpl
lateinit var focalAreaTarget: String
@Before
fun setUp() {
- whenever(wallpaperManager.isWallpaperSupported).thenReturn(true)
focalAreaTarget = context.resources.getString(SysUIR.string.focal_area_target)
}
@Test
fun wallpaperInfo_nullInfo() =
testScope.runTest {
+ underTest = kosmos.wallpaperRepository
val latest by collectLastValue(underTest.wallpaperInfo)
- whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(null)
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(null)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ broadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
Intent(Intent.ACTION_WALLPAPER_CHANGED),
)
@@ -96,11 +95,13 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
@Test
fun wallpaperInfo_hasInfoFromManager() =
testScope.runTest {
+ underTest = kosmos.wallpaperRepository
val latest by collectLastValue(underTest.wallpaperInfo)
- whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(UNSUPPORTED_WP)
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any()))
+ .thenReturn(UNSUPPORTED_WP)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ broadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
Intent(Intent.ACTION_WALLPAPER_CHANGED),
)
@@ -111,7 +112,8 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
@Test
fun wallpaperInfo_initialValueIsFetched() =
testScope.runTest {
- whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_SUPPORTED_WP.id))
+ underTest = kosmos.wallpaperRepository
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(USER_WITH_SUPPORTED_WP.id))
.thenReturn(SUPPORTED_WP)
userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP))
userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP)
@@ -126,15 +128,16 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
@Test
fun wallpaperInfo_updatesOnUserChanged() =
testScope.runTest {
+ underTest = kosmos.wallpaperRepository
val latest by collectLastValue(underTest.wallpaperInfo)
val user3 = UserInfo(/* id= */ 3, /* name= */ "user3", /* flags= */ 0)
val user3Wp = mock<WallpaperInfo>()
- whenever(wallpaperManager.getWallpaperInfoForUser(user3.id)).thenReturn(user3Wp)
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(user3.id)).thenReturn(user3Wp)
val user4 = UserInfo(/* id= */ 4, /* name= */ "user4", /* flags= */ 0)
val user4Wp = mock<WallpaperInfo>()
- whenever(wallpaperManager.getWallpaperInfoForUser(user4.id)).thenReturn(user4Wp)
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(user4.id)).thenReturn(user4Wp)
userRepository.setUserInfos(listOf(user3, user4))
@@ -154,15 +157,16 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
@Test
fun wallpaperInfo_doesNotUpdateOnUserChanging() =
testScope.runTest {
+ underTest = kosmos.wallpaperRepository
val latest by collectLastValue(underTest.wallpaperInfo)
val user3 = UserInfo(/* id= */ 3, /* name= */ "user3", /* flags= */ 0)
val user3Wp = mock<WallpaperInfo>()
- whenever(wallpaperManager.getWallpaperInfoForUser(user3.id)).thenReturn(user3Wp)
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(user3.id)).thenReturn(user3Wp)
val user4 = UserInfo(/* id= */ 4, /* name= */ "user4", /* flags= */ 0)
val user4Wp = mock<WallpaperInfo>()
- whenever(wallpaperManager.getWallpaperInfoForUser(user4.id)).thenReturn(user4Wp)
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(user4.id)).thenReturn(user4Wp)
userRepository.setUserInfos(listOf(user3, user4))
@@ -183,17 +187,18 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
@Test
fun wallpaperInfo_updatesOnIntent() =
testScope.runTest {
+ underTest = kosmos.wallpaperRepository
val latest by collectLastValue(underTest.wallpaperInfo)
val wp1 = mock<WallpaperInfo>()
- whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp1)
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp1)
assertThat(latest).isEqualTo(wp1)
// WHEN the info is new and a broadcast is sent
val wp2 = mock<WallpaperInfo>()
- whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp2)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp2)
+ broadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
Intent(Intent.ACTION_WALLPAPER_CHANGED),
)
@@ -205,15 +210,16 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
@Test
fun wallpaperInfo_wallpaperNotSupported_alwaysNull() =
testScope.runTest {
- whenever(wallpaperManager.isWallpaperSupported).thenReturn(false)
+ isWallpaperSupported = false
+ underTest = kosmos.wallpaperRepository
val latest by collectLastValue(underTest.wallpaperInfo)
assertThat(latest).isNull()
// Even WHEN there *is* current wallpaper
val wp1 = mock<WallpaperInfo>()
- whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp1)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp1)
+ broadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
Intent(Intent.ACTION_WALLPAPER_CHANGED),
)
@@ -226,6 +232,8 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
@EnableFlags(SharedFlags.FLAG_AMBIENT_AOD)
fun wallpaperSupportsAmbientMode_deviceDoesNotSupport_false() =
testScope.runTest {
+ underTest = kosmos.wallpaperRepository
+ secureSettings.putInt(Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED, 1)
context.orCreateTestableResources.addOverride(
R.bool.config_dozeSupportsAodWallpaper,
false,
@@ -239,6 +247,8 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
@EnableFlags(SharedFlags.FLAG_AMBIENT_AOD)
fun wallpaperSupportsAmbientMode_deviceDoesSupport_true() =
testScope.runTest {
+ underTest = kosmos.wallpaperRepository
+ secureSettings.putInt(Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED, 1)
context.orCreateTestableResources.addOverride(
R.bool.config_dozeSupportsAodWallpaper,
true,
@@ -249,54 +259,67 @@ class WallpaperRepositoryImplTest : SysuiTestCase() {
}
@Test
- @Ignore("ag/31591766")
+ @EnableFlags(SharedFlags.FLAG_AMBIENT_AOD)
+ fun wallpaperSupportsAmbientMode_deviceDoesSupport_settingDisabled_false() =
+ testScope.runTest {
+ underTest = kosmos.wallpaperRepository
+ secureSettings.putInt(Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED, 0)
+ context.orCreateTestableResources.addOverride(
+ R.bool.config_dozeSupportsAodWallpaper,
+ true,
+ )
+
+ val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode)
+ assertThat(latest).isFalse()
+ }
+
+ @Test
@EnableFlags(SharedFlags.FLAG_EXTENDED_WALLPAPER_EFFECTS)
fun shouldSendNotificationLayout_setExtendedEffectsWallpaper_launchSendLayoutJob() =
testScope.runTest {
+ underTest = kosmos.wallpaperRepository
val latest by collectLastValue(underTest.shouldSendFocalArea)
val extedendEffectsWallpaper =
mock<WallpaperInfo>().apply {
whenever(this.component).thenReturn(ComponentName(context, focalAreaTarget))
}
- whenever(wallpaperManager.getWallpaperInfoForUser(any()))
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any()))
.thenReturn(extedendEffectsWallpaper)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ broadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
Intent(Intent.ACTION_WALLPAPER_CHANGED),
)
assertThat(latest).isTrue()
- assertThat(underTest.sendLockscreenLayoutJob).isNotNull()
- assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true)
}
@Test
- @Ignore("ag/31591766")
@EnableFlags(SharedFlags.FLAG_EXTENDED_WALLPAPER_EFFECTS)
fun shouldSendNotificationLayout_setNotExtendedEffectsWallpaper_cancelSendLayoutJob() =
testScope.runTest {
+ underTest = kosmos.wallpaperRepository
val latest by collectLastValue(underTest.shouldSendFocalArea)
val extendedEffectsWallpaper =
mock<WallpaperInfo>().apply {
whenever(this.component).thenReturn(ComponentName("", focalAreaTarget))
}
- whenever(wallpaperManager.getWallpaperInfoForUser(any()))
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any()))
.thenReturn(extendedEffectsWallpaper)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ broadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
Intent(Intent.ACTION_WALLPAPER_CHANGED),
)
assertThat(latest).isTrue()
- assertThat(underTest.sendLockscreenLayoutJob).isNotNull()
- assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true)
- whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(UNSUPPORTED_WP)
- fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any()))
+ .thenReturn(UNSUPPORTED_WP)
+ broadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
Intent(Intent.ACTION_WALLPAPER_CHANGED),
)
+ runCurrent()
+
assertThat(latest).isFalse()
- assertThat(underTest.sendLockscreenLayoutJob?.isCancelled).isEqualTo(true)
}
private companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt
index cd6e18a69c4d..31a611cc984b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt
@@ -30,13 +30,8 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
-import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
-import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.testKosmos
-import com.android.systemui.wallpapers.data.repository.fakeWallpaperFocalAreaRepository
import com.android.systemui.wallpapers.data.repository.wallpaperFocalAreaRepository
-import com.android.systemui.wallpapers.data.repository.wallpaperRepository
import com.android.systemui.wallpapers.ui.viewmodel.wallpaperFocalAreaViewModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -77,40 +72,26 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() {
.thenReturn(2f)
underTest =
WallpaperFocalAreaInteractor(
- applicationScope = testScope.backgroundScope,
context = kosmos.mockedContext,
- wallpaperFocalAreaRepository = kosmos.fakeWallpaperFocalAreaRepository,
+ wallpaperFocalAreaRepository = kosmos.wallpaperFocalAreaRepository,
shadeRepository = kosmos.shadeRepository,
- activeNotificationsInteractor = kosmos.activeNotificationsInteractor,
- wallpaperRepository = kosmos.wallpaperRepository,
)
}
- private fun overrideMockedResources(overrideResources: OverrideResources) {
- val displayMetrics =
- DisplayMetrics().apply {
- widthPixels = overrideResources.screenWidth
- heightPixels = overrideResources.screenHeight
- density = 2f
- }
- whenever(mockedResources.displayMetrics).thenReturn(displayMetrics)
- whenever(mockedResources.getBoolean(R.bool.center_align_focal_area_shape))
- .thenReturn(overrideResources.centerAlignFocalArea)
- }
-
@Test
fun focalAreaBounds_withoutNotifications_inHandheldDevices() =
testScope.runTest {
overrideMockedResources(
+ mockedResources,
OverrideResources(
screenWidth = 1000,
screenHeight = 2000,
centerAlignFocalArea = false,
- )
+ ),
)
val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
kosmos.shadeRepository.setShadeLayoutWide(false)
- kosmos.activeNotificationListRepository.setActiveNotifs(0)
+
kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(400F)
@@ -122,15 +103,15 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() {
fun focalAreaBounds_withNotifications_inHandheldDevices() =
testScope.runTest {
overrideMockedResources(
+ mockedResources,
OverrideResources(
screenWidth = 1000,
screenHeight = 2000,
centerAlignFocalArea = false,
- )
+ ),
)
val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
kosmos.shadeRepository.setShadeLayoutWide(false)
- kosmos.activeNotificationListRepository.setActiveNotifs(1)
kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(600F)
@@ -139,58 +120,38 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() {
}
@Test
- fun focalAreaBounds_withNotifications_inUnfoldLandscape() =
+ fun focalAreaBounds_inUnfoldLandscape() =
testScope.runTest {
overrideMockedResources(
+ mockedResources,
OverrideResources(
screenWidth = 2000,
screenHeight = 1600,
centerAlignFocalArea = false,
- )
+ ),
)
val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
kosmos.shadeRepository.setShadeLayoutWide(true)
- kosmos.activeNotificationListRepository.setActiveNotifs(1)
- kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1400F)
- kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
- kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(600F)
-
- assertThat(bounds).isEqualTo(RectF(500f, 600F, 1000F, 1100F))
- }
-
- @Test
- fun focalAreaBounds_withoutNotifications_inUnfoldLandscape() =
- testScope.runTest {
- overrideMockedResources(
- OverrideResources(
- screenWidth = 2000,
- screenHeight = 1600,
- centerAlignFocalArea = false,
- )
- )
- val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
- kosmos.shadeRepository.setShadeLayoutWide(true)
- kosmos.activeNotificationListRepository.setActiveNotifs(0)
kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1400F)
kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(400F)
- assertThat(bounds).isEqualTo(RectF(1000f, 600F, 1500F, 1100F))
+ assertThat(bounds).isEqualTo(RectF(600f, 600F, 1400F, 1100F))
}
@Test
fun focalAreaBounds_withNotifications_inUnfoldPortrait() =
testScope.runTest {
overrideMockedResources(
+ mockedResources,
OverrideResources(
screenWidth = 1600,
screenHeight = 2000,
centerAlignFocalArea = false,
- )
+ ),
)
val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
kosmos.shadeRepository.setShadeLayoutWide(false)
- kosmos.activeNotificationListRepository.setActiveNotifs(1)
kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(600F)
@@ -202,15 +163,15 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() {
fun focalAreaBounds_withoutNotifications_inUnfoldPortrait() =
testScope.runTest {
overrideMockedResources(
+ mockedResources,
OverrideResources(
screenWidth = 1600,
screenHeight = 2000,
centerAlignFocalArea = false,
- )
+ ),
)
val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
kosmos.shadeRepository.setShadeLayoutWide(false)
- kosmos.activeNotificationListRepository.setActiveNotifs(0)
kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(600F)
@@ -219,18 +180,18 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() {
}
@Test
- fun focalAreaBounds_withNotifications_inTabletLandscape() =
+ fun focalAreaBounds_inTabletLandscape() =
testScope.runTest {
overrideMockedResources(
+ mockedResources,
OverrideResources(
screenWidth = 3000,
screenHeight = 2000,
centerAlignFocalArea = true,
- )
+ ),
)
val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
kosmos.shadeRepository.setShadeLayoutWide(true)
- kosmos.activeNotificationListRepository.setActiveNotifs(1)
kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(200F)
kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(200F)
@@ -239,35 +200,16 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() {
}
@Test
- fun focalAreaBounds_withoutNotifications_inTabletLandscape() =
- testScope.runTest {
- overrideMockedResources(
- OverrideResources(
- screenWidth = 3000,
- screenHeight = 2000,
- centerAlignFocalArea = true,
- )
- )
- val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
- kosmos.shadeRepository.setShadeLayoutWide(true)
- kosmos.activeNotificationListRepository.setActiveNotifs(0)
- kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(1800F)
- kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(400F)
- kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(400F)
-
- assertThat(bounds).isEqualTo(RectF(1000f, 600F, 2000F, 1400F))
- }
-
- @Test
fun onTap_inFocalBounds() =
testScope.runTest {
kosmos.wallpaperFocalAreaRepository.setTapPosition(PointF(0F, 0F))
overrideMockedResources(
+ mockedResources,
OverrideResources(
screenWidth = 1000,
screenHeight = 2000,
centerAlignFocalArea = false,
- )
+ ),
)
kosmos.wallpaperFocalAreaRepository.setWallpaperFocalAreaBounds(
RectF(250f, 700F, 750F, 1400F)
@@ -287,11 +229,12 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() {
testScope.runTest {
kosmos.wallpaperFocalAreaRepository.setTapPosition(PointF(0F, 0F))
overrideMockedResources(
+ mockedResources,
OverrideResources(
screenWidth = 1000,
screenHeight = 2000,
centerAlignFocalArea = false,
- )
+ ),
)
kosmos.wallpaperFocalAreaViewModel = mock()
kosmos.wallpaperFocalAreaRepository.setWallpaperFocalAreaBounds(
@@ -309,4 +252,21 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() {
val screenHeight: Int,
val centerAlignFocalArea: Boolean,
)
+
+ companion object {
+ fun overrideMockedResources(
+ mockedResources: Resources,
+ overrideResources: OverrideResources,
+ ) {
+ val displayMetrics =
+ DisplayMetrics().apply {
+ widthPixels = overrideResources.screenWidth
+ heightPixels = overrideResources.screenHeight
+ density = 2f
+ }
+ whenever(mockedResources.displayMetrics).thenReturn(displayMetrics)
+ whenever(mockedResources.getBoolean(R.bool.center_align_focal_area_shape))
+ .thenReturn(overrideResources.centerAlignFocalArea)
+ }
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModelTest.kt
new file mode 100644
index 000000000000..3cd20721a15b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModelTest.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallpapers.ui.viewmodel
+
+import android.content.mockedContext
+import android.content.res.Resources
+import android.graphics.RectF
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
+import com.android.systemui.testKosmos
+import com.android.systemui.wallpapers.data.repository.wallpaperFocalAreaRepository
+import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor
+import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractorTest.Companion.overrideMockedResources
+import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractorTest.OverrideResources
+import com.android.systemui.wallpapers.domain.interactor.wallpaperFocalAreaInteractor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WallpaperFocalAreaViewModelTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private lateinit var mockedResources: Resources
+ lateinit var underTest: WallpaperFocalAreaViewModel
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ mockedResources = mock<Resources>()
+ overrideMockedResources(
+ mockedResources,
+ OverrideResources(screenWidth = 1000, screenHeight = 2000, centerAlignFocalArea = false),
+ )
+ whenever(kosmos.mockedContext.resources).thenReturn(mockedResources)
+ whenever(
+ mockedResources.getFloat(
+ Resources.getSystem()
+ .getIdentifier(
+ /* name= */ "config_wallpaperMaxScale",
+ /* defType= */ "dimen",
+ /* defPackage= */ "android",
+ )
+ )
+ )
+ .thenReturn(2f)
+ kosmos.wallpaperFocalAreaInteractor =
+ WallpaperFocalAreaInteractor(
+ context = kosmos.mockedContext,
+ wallpaperFocalAreaRepository = kosmos.wallpaperFocalAreaRepository,
+ shadeRepository = kosmos.shadeRepository,
+ )
+ underTest =
+ WallpaperFocalAreaViewModel(
+ wallpaperFocalAreaInteractor = kosmos.wallpaperFocalAreaInteractor,
+ keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor,
+ )
+ }
+
+ @Test
+ fun focalAreaBoundsSent_whenFinishTransitioningToLockscreen() =
+ testScope.runTest {
+ overrideMockedResources(
+ mockedResources,
+ OverrideResources(
+ screenWidth = 1600,
+ screenHeight = 2000,
+ centerAlignFocalArea = false,
+ ),
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ listOf(
+ TransitionStep(transitionState = TransitionState.STARTED, to = LOCKSCREEN),
+ TransitionStep(transitionState = TransitionState.FINISHED, to = LOCKSCREEN),
+ ),
+ testScope,
+ )
+
+ setTestFocalAreaBounds()
+
+ assertThat(bounds).isEqualTo(RectF(400F, 510F, 1200F, 700F))
+ }
+
+ @Test
+ fun focalAreaBoundsNotSent_whenNotFinishTransitioningToLockscreen() =
+ testScope.runTest {
+ overrideMockedResources(
+ mockedResources,
+ OverrideResources(
+ screenWidth = 1600,
+ screenHeight = 2000,
+ centerAlignFocalArea = false,
+ ),
+ )
+ val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds)
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ listOf(TransitionStep(transitionState = TransitionState.STARTED, to = LOCKSCREEN)),
+ testScope,
+ )
+ setTestFocalAreaBounds()
+
+ assertThat(bounds).isEqualTo(null)
+ }
+
+ private fun setTestFocalAreaBounds() {
+ kosmos.shadeRepository.setShadeLayoutWide(false)
+ kosmos.activeNotificationListRepository.setActiveNotifs(0)
+ kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(400F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(20F)
+ kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(20F)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModelTest.kt
index 390518f3e2e5..3da4f29a6fcb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModelTest.kt
@@ -23,32 +23,28 @@ import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
-import com.android.systemui.lifecycle.activateIn
import com.android.systemui.testKosmos
+import com.android.systemui.window.data.repository.fakeWindowRootViewBlurRepository
+import com.android.systemui.window.data.repository.windowRootViewBlurRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
-@EnableFlags(Flags.FLAG_BOUNCER_UI_REVAMP)
+@EnableFlags(Flags.FLAG_BOUNCER_UI_REVAMP, Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND)
class WindowRootViewModelTest : SysuiTestCase() {
val kosmos = testKosmos()
val testScope = kosmos.testScope
val underTest by lazy { kosmos.windowRootViewModel }
- @Before
- fun setup() {
- underTest.activateIn(testScope)
- }
-
@Test
fun bouncerTransitionChangesWindowBlurRadius() =
testScope.runTest {
+ kosmos.fakeWindowRootViewBlurRepository.isBlurSupported.value = true
val blurRadius by collectLastValue(underTest.blurRadius)
val isBlurOpaque by collectLastValue(underTest.isBlurOpaque)
runCurrent()
@@ -59,4 +55,27 @@ class WindowRootViewModelTest : SysuiTestCase() {
assertThat(blurRadius).isEqualTo(30)
assertThat(isBlurOpaque).isEqualTo(false)
}
+
+ @Test
+ fun blurRadiusDoesNotChangeWhenBlurIsNotSupported() =
+ testScope.runTest {
+ kosmos.fakeWindowRootViewBlurRepository.isBlurSupported.value = false
+ val blurRadius by collectLastValue(underTest.blurRadius)
+ runCurrent()
+
+ kosmos.fakeBouncerTransitions.first().windowBlurRadius.value = 30.0f
+ runCurrent()
+
+ assertThat(blurRadius).isEqualTo(0f)
+
+ kosmos.fakeGlanceableHubTransitions.first().windowBlurRadius.value = 50.0f
+ runCurrent()
+
+ assertThat(blurRadius).isEqualTo(0f)
+
+ kosmos.windowRootViewBlurRepository.blurRadius.value = 60
+ runCurrent()
+
+ assertThat(blurRadius).isEqualTo(0f)
+ }
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
index 9a837446a802..3ed321e48cd3 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
@@ -83,6 +83,13 @@ class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) :
}
}
+ fun updateAxes(lsFVar: String, aodFVar: String) {
+ i({ "updateAxes(LS = $str1, AOD = $str2)" }) {
+ str1 = lsFVar
+ str2 = aodFVar
+ }
+ }
+
fun addView(child: View) {
d({ "addView($str1 @$int1)" }) {
str1 = child::class.simpleName!!
@@ -90,6 +97,14 @@ class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) :
}
}
+ fun animateDoze() {
+ d("animateDoze()")
+ }
+
+ fun animateCharge() {
+ d("animateCharge()")
+ }
+
fun animateFidget(x: Float, y: Float) {
d({ "animateFidget($str1, $str2)" }) {
str1 = x.toString()
diff --git a/packages/SystemUI/res-keyguard/drawable/pin_bouncer_confirm.xml b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_confirm.xml
new file mode 100644
index 000000000000..a27e29f1beb6
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_confirm.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="40dp"
+ android:height="40dp"
+ android:viewportHeight="40"
+ android:viewportWidth="40">
+ <group>
+ <clip-path android:pathData="M8,12h24.5v15.5h-24.5z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M30.75,12C29.79,12 29,12.79 29,13.75V25.75C29,26.71 29.79,27.5 30.75,27.5C31.71,27.5 32.5,26.71 32.5,25.75V13.75C32.5,12.79 31.71,12 30.75,12Z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M20.98,12.92C20.3,12.24 19.19,12.24 18.51,12.92C17.83,13.6 17.83,14.71 18.51,15.39L21.12,18H9.75C8.79,18 8,18.79 8,19.75C8,20.71 8.79,21.5 9.75,21.5H21.11L18.51,24.1C18.18,24.43 18,24.87 18,25.34C18,25.81 18.18,26.25 18.52,26.58C18.86,26.92 19.31,27.09 19.75,27.09C20.19,27.09 20.65,26.92 20.99,26.58L26.61,20.96C27.28,20.29 27.28,19.21 26.61,18.55L20.98,12.92Z" />
+ </group>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_filled.xml b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_filled.xml
new file mode 100644
index 000000000000..86f95bc97169
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_filled.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="40dp"
+ android:height="40dp"
+ android:viewportHeight="40"
+ android:viewportWidth="40">
+ <path
+ android:fillColor="#000000"
+ android:pathData="M22.167,21.9L25.531,25.265C25.795,25.502 26.112,25.621 26.481,25.621C26.851,25.621 27.167,25.502 27.431,25.265C27.669,25.001 27.788,24.684 27.788,24.315C27.788,23.919 27.669,23.589 27.431,23.325L24.067,20L27.392,16.675C27.656,16.411 27.788,16.094 27.788,15.725C27.788,15.356 27.656,15.039 27.392,14.775C27.128,14.511 26.798,14.379 26.402,14.379C26.033,14.379 25.729,14.511 25.492,14.775L22.167,18.1L18.802,14.735C18.538,14.498 18.222,14.379 17.852,14.379C17.483,14.379 17.166,14.498 16.902,14.735C16.665,14.999 16.546,15.329 16.546,15.725C16.546,16.094 16.665,16.411 16.902,16.675L20.267,20L16.902,23.325C16.665,23.589 16.546,23.906 16.546,24.275C16.546,24.644 16.665,24.961 16.902,25.225C17.166,25.489 17.483,25.621 17.852,25.621C18.248,25.621 18.578,25.489 18.842,25.225L22.167,21.9ZM14.012,32.667C13.59,32.667 13.181,32.574 12.785,32.39C12.416,32.179 12.099,31.915 11.835,31.598L4.394,21.623C4.024,21.148 3.84,20.607 3.84,20C3.84,19.393 4.024,18.852 4.394,18.377L11.835,8.402C12.073,8.085 12.39,7.835 12.785,7.65C13.181,7.439 13.59,7.333 14.012,7.333H32.142C32.907,7.333 33.554,7.597 34.081,8.125C34.609,8.653 34.873,9.286 34.873,10.025V29.975C34.873,30.714 34.609,31.347 34.081,31.875C33.554,32.403 32.907,32.667 32.142,32.667H14.012Z" />
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_outline.xml b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_outline.xml
new file mode 100644
index 000000000000..7f551f4d3c60
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_outline.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="40dp"
+ android:height="40dp"
+ android:viewportHeight="40"
+ android:viewportWidth="40">
+ <group>
+ <clip-path android:pathData="M5,7h29.89v25h-29.89z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M30.96,32H15.59C14.21,32 12.89,31.34 12.06,30.24L5.78,21.86C4.74,20.47 4.74,18.54 5.78,17.15L12.06,8.77C12.89,7.67 14.21,7 15.59,7H30.96C33.13,7 34.89,8.76 34.89,10.93V28.08C34.89,30.25 33.13,32.01 30.96,32.01V32ZM14.46,28.44C14.73,28.79 15.15,29 15.59,29H30.96C31.47,29 31.89,28.58 31.89,28.07V10.93C31.89,10.42 31.47,10 30.96,10H15.59C15.15,10 14.73,10.21 14.46,10.56L8.18,18.94C7.93,19.27 7.93,19.72 8.18,20.05L14.46,28.43V28.44Z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M22.46,21.27L25.36,24.17C25.6,24.43 25.89,24.56 26.25,24.56C26.61,24.56 26.9,24.43 27.14,24.17C27.4,23.93 27.53,23.64 27.53,23.28C27.53,22.92 27.4,22.63 27.14,22.39L24.24,19.49L27.14,16.59C27.38,16.35 27.49,16.06 27.49,15.7C27.49,15.34 27.37,15.05 27.14,14.81C26.91,14.57 26.61,14.46 26.25,14.46C25.89,14.46 25.59,14.58 25.33,14.81L22.46,17.71L19.56,14.81C19.32,14.55 19.03,14.42 18.67,14.42C18.31,14.42 18.02,14.55 17.78,14.81C17.52,15.05 17.39,15.34 17.39,15.7C17.39,16.06 17.52,16.35 17.78,16.59L20.68,19.49L17.78,22.39C17.52,22.63 17.39,22.92 17.39,23.28C17.39,23.64 17.52,23.93 17.78,24.17C18.02,24.41 18.31,24.52 18.67,24.52C19.03,24.52 19.32,24.4 19.56,24.17L22.46,21.27Z" />
+ </group>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
index 0b35559148af..87d06bfde743 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
@@ -21,7 +21,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/keyguard_lock_padding"
- android:importantForAccessibility="no"
+ android:accessibilityLiveRegion="polite"
android:ellipsize="marquee"
android:focusable="false"
android:gravity="center"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_motion_layout.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_motion_layout.xml
index f231df2f1a10..c7f320c69113 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_motion_layout.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_motion_layout.xml
@@ -67,6 +67,7 @@
<com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:screenReaderFocusable="true"
+ android:accessibilityLiveRegion="polite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
index 04457229d573..9359838238af 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -32,6 +32,7 @@
<com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:screenReaderFocusable="true"
+ android:accessibilityLiveRegion="polite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml
index b184344f2f24..6cbe96a8cb50 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml
@@ -68,6 +68,7 @@
<com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:screenReaderFocusable="true"
+ android:accessibilityLiveRegion="polite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index 0e15ff66f3ee..cf388875a174 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -36,6 +36,7 @@
<com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:screenReaderFocusable="true"
+ android:accessibilityLiveRegion="polite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml
index f6ac02aee657..33eab179c3f7 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml
@@ -75,6 +75,7 @@
<com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:screenReaderFocusable="true"
+ android:accessibilityLiveRegion="polite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index ba4da794d777..fd5eeb8b9408 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -33,6 +33,7 @@
<com.android.systemui.bouncer.ui.BouncerMessageView
android:id="@+id/bouncer_message_view"
android:screenReaderFocusable="true"
+ android:accessibilityLiveRegion="polite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index baef51ae9d48..249cc6c215eb 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -34,7 +34,7 @@
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Brzo punjenje"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sporo punjenje"</string>
<string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje je na čekanju radi zaštite baterije"</string>
- <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Provjera dodatne opreme za punjenje"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Provjera dodatka za punjenje"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Neupotrebljiv SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 7560621d382c..55d9374f341f 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -23,7 +23,7 @@
<string name="keyguard_enter_your_pin" msgid="5429932527814874032">"ನಿಮ್ಮ ಪಿನ್ ನಮೂದಿಸಿ"</string>
<string name="keyguard_enter_pin" msgid="8114529922480276834">"ಪಿನ್ ನಮೂದಿಸಿ"</string>
<string name="keyguard_enter_your_pattern" msgid="351503370332324745">"ನಿಮ್ಮ ಪ್ಯಾಟರ್ನ್ ನಮೂದಿಸಿ"</string>
- <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಬಿಡಿಸಿ"</string>
+ <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಬರೆಯಿರಿ"</string>
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ನಮೂದಿಸಿ"</string>
<string name="keyguard_enter_password" msgid="6483623792371009758">"ಪಾಸ್‌ವರ್ಡ್ ನಮೂದಿಸಿ"</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ಅಮಾನ್ಯ ಕಾರ್ಡ್."</string>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index bfb37a0d97a7..6d446453d9f7 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -31,6 +31,10 @@
<!-- height for the keyguard pin input field -->
<dimen name="keyguard_pin_field_height">56dp</dimen>
+ <dimen name="keyguard_pattern_dot_size">16dp</dimen>
+ <dimen name="keyguard_pattern_activated_dot_size">24dp</dimen>
+ <dimen name="keyguard_pattern_stroke_width">32dp</dimen>
+
<!-- height for the keyguard password input field -->
<dimen name="keyguard_password_field_height">56dp</dimen>
diff --git a/packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml b/packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml
new file mode 100644
index 000000000000..4e402cf530e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/textColorPrimary"
+ android:autoMirrored="true">
+ <path android:fillColor="#FFFFFFFF"
+ android:pathData="M19.8,22.6 L16.775,19.575Q16.15,19.975 15.45,20.263Q14.75,20.55 14,20.725V18.675Q14.35,18.55 14.688,18.425Q15.025,18.3 15.325,18.125L12,14.8V20L7,15H3V9H6.2L1.4,4.2L2.8,2.8L21.2,21.2ZM19.6,16.8 L18.15,15.35Q18.575,14.575 18.788,13.725Q19,12.875 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,13.3 20.638,14.525Q20.275,15.75 19.6,16.8ZM16.25,13.45 L14,11.2V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,12.375 16.438,12.738Q16.375,13.1 16.25,13.45ZM12,9.2 L9.4,6.6 12,4ZM10,15.15V12.8L8.2,11H5V13H7.85ZM9.1,11.9Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml b/packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml
new file mode 100644
index 000000000000..2a90e051b83b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/textColorPrimary"
+ android:autoMirrored="true">
+ <path android:fillColor="#FFFFFFFF"
+ android:pathData="M14,20.725V18.675Q16.25,18.025 17.625,16.175Q19,14.325 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,15.15 19.05,17.587Q17.1,20.025 14,20.725ZM3,15V9H7L12,4V20L7,15ZM14,16V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,13.275 15.838,14.362Q15.175,15.45 14,16ZM10,8.85 L7.85,11H5V13H7.85L10,15.15ZM7.5,12Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml
new file mode 100644
index 000000000000..b18e0a7aae60
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="19dp"
+ android:width="19dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:tint="?android:attr/textColorPrimary">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_speaker_mute.xml b/packages/SystemUI/res/drawable/ic_speaker_mute.xml
index 4e402cf530e4..bf31580f3bb0 100644
--- a/packages/SystemUI/res/drawable/ic_speaker_mute.xml
+++ b/packages/SystemUI/res/drawable/ic_speaker_mute.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2025 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,15 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?android:attr/textColorPrimary"
- android:autoMirrored="true">
- <path android:fillColor="#FFFFFFFF"
- android:pathData="M19.8,22.6 L16.775,19.575Q16.15,19.975 15.45,20.263Q14.75,20.55 14,20.725V18.675Q14.35,18.55 14.688,18.425Q15.025,18.3 15.325,18.125L12,14.8V20L7,15H3V9H6.2L1.4,4.2L2.8,2.8L21.2,21.2ZM19.6,16.8 L18.15,15.35Q18.575,14.575 18.788,13.725Q19,12.875 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,13.3 20.638,14.525Q20.275,15.75 19.6,16.8ZM16.25,13.45 L14,11.2V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,12.375 16.438,12.738Q16.375,13.1 16.25,13.45ZM12,9.2 L9.4,6.6 12,4ZM10,15.15V12.8L8.2,11H5V13H7.85ZM9.1,11.9Z"/>
-</vector> \ No newline at end of file
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <group>
+ <clip-path
+ android:pathData="M0,0h20v20h-20z"/>
+ <path
+ android:pathData="M16,18.125L13.771,15.896C13.465,16.09 13.097,16.278 12.667,16.458C12.25,16.625 11.861,16.75 11.5,16.833V15.292C11.667,15.222 11.861,15.146 12.083,15.063C12.319,14.965 12.514,14.875 12.667,14.792L10,12.125V16.021L6,12.021H3V8.021H5.875L1.875,4L2.938,2.938L17.063,17.063L16,18.125ZM15.875,13.771L14.792,12.688C15.014,12.285 15.188,11.861 15.313,11.417C15.438,10.958 15.5,10.493 15.5,10.021C15.5,8.785 15.125,7.688 14.375,6.729C13.639,5.757 12.681,5.09 11.5,4.729V3.188C13.125,3.507 14.444,4.313 15.458,5.604C16.486,6.896 17,8.368 17,10.021C17,10.688 16.903,11.34 16.708,11.979C16.514,12.604 16.236,13.201 15.875,13.771ZM13.292,11.188L11.5,9.396V6.854C12.125,7.132 12.611,7.563 12.958,8.146C13.319,8.715 13.5,9.34 13.5,10.021C13.5,10.215 13.486,10.41 13.458,10.604C13.431,10.799 13.375,10.993 13.292,11.188ZM10,7.896L8.063,5.958L10,4.021V7.896Z"
+ android:fillColor="#ECDFE5"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_speaker_on.xml b/packages/SystemUI/res/drawable/ic_speaker_on.xml
index 2a90e051b83b..f0d057e1b093 100644
--- a/packages/SystemUI/res/drawable/ic_speaker_on.xml
+++ b/packages/SystemUI/res/drawable/ic_speaker_on.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2025 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,15 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?android:attr/textColorPrimary"
- android:autoMirrored="true">
- <path android:fillColor="#FFFFFFFF"
- android:pathData="M14,20.725V18.675Q16.25,18.025 17.625,16.175Q19,14.325 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,15.15 19.05,17.587Q17.1,20.025 14,20.725ZM3,15V9H7L12,4V20L7,15ZM14,16V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,13.275 15.838,14.362Q15.175,15.45 14,16ZM10,8.85 L7.85,11H5V13H7.85L10,15.15ZM7.5,12Z"/>
-</vector> \ No newline at end of file
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <group>
+ <clip-path
+ android:pathData="M0,0h20v20h-20z"/>
+ <path
+ android:pathData="M11.5,16.833V15.271C12.694,14.951 13.66,14.306 14.396,13.333C15.132,12.347 15.5,11.236 15.5,10C15.5,8.764 15.125,7.667 14.375,6.708C13.639,5.736 12.681,5.069 11.5,4.708V3.146C13.111,3.493 14.431,4.306 15.458,5.583C16.486,6.861 17,8.326 17,9.979C17,11.632 16.486,13.104 15.458,14.396C14.444,15.674 13.125,16.486 11.5,16.833ZM3,11.979V7.979H6L10,3.979V15.979L6,11.979H3ZM11.5,13.125V6.833C12.125,7.111 12.611,7.535 12.958,8.104C13.319,8.674 13.5,9.299 13.5,9.979C13.5,10.66 13.319,11.285 12.958,11.854C12.611,12.41 12.125,12.833 11.5,13.125Z"
+ android:fillColor="#ECDFE5"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
index b18e0a7aae60..2cbbb0da8de7 100644
--- a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
@@ -1,27 +1,28 @@
<!--
- Copyright (C) 2017 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.
--->
+ ~ Copyright (C) 2025 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.
+ -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="19dp"
- android:width="19dp"
- android:viewportHeight="24.0"
- android:viewportWidth="24.0"
- android:tint="?android:attr/textColorPrimary">
-
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <group>
+ <clip-path
+ android:pathData="M0,0h20v20h-20z"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/>
-
+ android:pathData="M0,12.5V7.5H1.5V12.5H0ZM2.5,14V6H4V14H2.5ZM18.5,12.5V7.5H20V12.5H18.5ZM16,14V6H17.5V14H16ZM6.5,17C6.083,17 5.729,16.854 5.438,16.563C5.146,16.271 5,15.917 5,15.5V4.5C5,4.083 5.146,3.729 5.438,3.438C5.729,3.146 6.083,3 6.5,3H13.5C13.917,3 14.271,3.146 14.563,3.438C14.854,3.729 15,4.083 15,4.5V15.5C15,15.917 14.854,16.271 14.563,16.563C14.271,16.854 13.917,17 13.5,17H6.5Z"
+ android:fillColor="#ECDFE5"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml b/packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml
new file mode 100644
index 000000000000..7b55b3c6fb56
--- /dev/null
+++ b/packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle"
+ >
+ <corners
+ android:topLeftRadius="0dp"
+ android:topRightRadius="@dimen/status_bar_mobile_container_corner_radius_updated"
+ android:bottomRightRadius="0dp"
+ android:bottomLeftRadius="@dimen/status_bar_mobile_container_corner_radius_updated"/>
+ <solid android:color="#FFF" />
+ <padding
+ android:left="2sp"
+ android:right="2sp"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
index b83f15a1a247..c0cb5ef61ca8 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
@@ -14,4 +14,4 @@ Copyright (C) 2015 The Android Open Source Project
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_speaker_mute" />
+ android:drawable="@drawable/ic_legacy_speaker_mute" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
index 21a4c1703d31..4d68d674c259 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
@@ -16,4 +16,4 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="2.5dp"
android:insetRight="2.5dp"
- android:drawable="@drawable/ic_volume_ringer_vibrate" /> \ No newline at end of file
+ android:drawable="@drawable/ic_legacy_volume_ringer_vibrate" /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/battery_status_chip.xml b/packages/SystemUI/res/layout/battery_status_chip.xml
index 74371839e247..7399651d4248 100644
--- a/packages/SystemUI/res/layout/battery_status_chip.xml
+++ b/packages/SystemUI/res/layout/battery_status_chip.xml
@@ -24,21 +24,13 @@
<LinearLayout
android:id="@+id/rounded_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/ongoing_appops_chip_height"
- android:layout_gravity="center"
- android:background="@drawable/statusbar_chip_bg"
- android:clipToOutline="true"
- android:gravity="center"
- android:maxWidth="@dimen/ongoing_appops_chip_max_width"
- android:minWidth="@dimen/ongoing_appops_chip_min_width">
+ style="@style/StatusBar.EventChip">
<com.android.systemui.battery.BatteryMeterView
android:id="@+id/battery_meter_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="10dp" />
+ android:layout_marginHorizontal="@dimen/ongoing_appops_chip_content_horizontal_margin" />
</LinearLayout>
</merge> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bindable_status_bar_compose_icon.xml b/packages/SystemUI/res/layout/bindable_status_bar_compose_icon.xml
new file mode 100644
index 000000000000..fa9318bc151c
--- /dev/null
+++ b/packages/SystemUI/res/layout/bindable_status_bar_compose_icon.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Base layout that provides a single bindable compose view -->
+<com.android.systemui.statusbar.pipeline.shared.ui.view.SingleBindableStatusBarComposeIconView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ >
+
+ <androidx.compose.ui.platform.ComposeView
+ android:id="@+id/compose_view"
+ android:layout_height="@dimen/status_bar_bindable_icon_size"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:padding="4sp"
+ />
+
+</com.android.systemui.statusbar.pipeline.shared.ui.view.SingleBindableStatusBarComposeIconView>
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 5922a7dcdcf0..67e97010ff22 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -131,7 +131,7 @@
style="@style/InternetDialog.Network">
<FrameLayout
- android:layout_width="24dp"
+ android:layout_width="wrap_content"
android:layout_height="24dp"
android:clickable="false"
android:layout_gravity="center_vertical|start">
diff --git a/packages/SystemUI/res/layout/magic_action_button.xml b/packages/SystemUI/res/layout/magic_action_button.xml
index 82d8d7043ff0..381d6b17dec5 100644
--- a/packages/SystemUI/res/layout/magic_action_button.xml
+++ b/packages/SystemUI/res/layout/magic_action_button.xml
@@ -1,4 +1,5 @@
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.notification.row.MagicActionButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
style="@android:style/Widget.Material.Button"
android:layout_width="wrap_content"
android:layout_height="@dimen/magic_action_button_touch_target_height"
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index 109e63c6167a..4472373f99a6 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -93,7 +93,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
- app:layout_constraintGuide_end="@dimen/qs_media_session_collapsed_guideline" />
+ app:layout_constraintGuide_end="@dimen/qs_media_session_collapsed_legacy_guideline" />
<!-- App icon -->
<com.android.internal.widget.CachingIconView
diff --git a/packages/SystemUI/res/layout/notification_2025_hybrid.xml b/packages/SystemUI/res/layout/notification_2025_hybrid.xml
index 8fd10fb3ddb8..8c34cd4165e0 100644
--- a/packages/SystemUI/res/layout/notification_2025_hybrid.xml
+++ b/packages/SystemUI/res/layout/notification_2025_hybrid.xml
@@ -29,7 +29,6 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
- android:textSize="@*android:dimen/notification_2025_title_text_size"
android:paddingEnd="4dp"
/>
<TextView
diff --git a/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
index 35f2ef901bdd..a338e4c70cfa 100644
--- a/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
+++ b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
@@ -54,7 +54,6 @@
android:singleLine="true"
android:paddingEnd="4dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
- android:textSize="@*android:dimen/notification_2025_title_text_size"
/>
<TextView
diff --git a/packages/SystemUI/res/layout/promoted_notification_info.xml b/packages/SystemUI/res/layout/promoted_notification_info.xml
index 5d170a98a806..2e0a0ca1185c 100644
--- a/packages/SystemUI/res/layout/promoted_notification_info.xml
+++ b/packages/SystemUI/res/layout/promoted_notification_info.xml
@@ -323,31 +323,43 @@ asked for it -->
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="60dp"
+ android:layout_marginTop="@dimen/notification_importance_button_separation"
android:gravity="center_vertical"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
+ android:background="@drawable/rounded_corners"
+ android:backgroundTint="@androidprv:color/materialColorPrimaryContainer"
>
<TextView
- android:id="@+id/promoted_demote"
- android:text="@string/notification_inline_disable_promotion"
- android:layout_width="wrap_content"
+ android:id="@+id/promoted_explain_title"
+ android:text="@string/live_notifications_title"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:gravity="start|center_vertical"
- android:minWidth="@dimen/notification_importance_toggle_size"
- android:minHeight="@dimen/notification_importance_toggle_size"
- android:maxWidth="200dp"
+ android:padding="16dp"
+ android:color="@androidprv:color/materialColorOnPrimary"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
- android:id="@+id/promoted_dismiss"
- android:text="@string/notification_inline_dismiss"
+ android:id="@+id/promoted_explain"
+ android:text="@string/live_notifications_desc"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/promoted_explain_title"
+ android:gravity="start|center_vertical"
+ android:maxWidth="200dp"
+ android:padding="16dp"
+ style="@style/TextAppearance.NotificationImportanceDetail"/>
+ <TextView
+ android:id="@+id/promoted_demote"
+ android:text="@string/notification_inline_disable_promotion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_below="@id/promoted_explain"
android:layout_alignParentEnd="true"
- android:gravity="end|center_vertical"
+ android:padding="16dp"
+ android:gravity="start|center_vertical"
android:minWidth="@dimen/notification_importance_toggle_size"
android:minHeight="@dimen/notification_importance_toggle_size"
- android:maxWidth="125dp"
+ android:maxWidth="200dp"
style="@style/TextAppearance.NotificationInfo.Button"/>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_event_chip_compose.xml b/packages/SystemUI/res/layout/status_bar_event_chip_compose.xml
new file mode 100644
index 000000000000..ff96ab15cd15
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_event_chip_compose.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2025 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.
+ -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical|end">
+
+ <LinearLayout
+ android:id="@+id/rounded_container"
+ style="@style/StatusBar.EventChip">
+
+ <!-- Stub for the composable -->
+ <androidx.compose.ui.platform.ComposeView
+ android:id="@+id/compose_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/ongoing_appops_chip_content_horizontal_margin" />
+
+ </LinearLayout>
+</merge>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 8ad99abccdfe..889aefed0c5c 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -14,7 +14,6 @@
limitations under the License.
-->
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/volume_dialog"
android:layout_width="match_parent"
@@ -30,42 +29,47 @@
android:layout_marginTop="@dimen/volume_dialog_background_top_margin"
android:layout_marginBottom="@dimen/volume_dialog_background_vertical_margin"
android:background="@drawable/volume_dialog_background"
- app:layout_constraintBottom_toBottomOf="@id/volume_dialog_settings"
+ app:layout_constraintBottom_toBottomOf="@id/volume_dialog_bottom_section_container"
app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
app:layout_constraintTop_toTopOf="@id/volume_dialog_main_slider_container" />
- <include
- android:id="@id/volume_ringer_drawer"
- layout="@layout/volume_ringer_drawer"
+ <FrameLayout
+ android:id="@+id/volume_dialog_top_section_container"
android:layout_width="0dp"
android:layout_height="0dp"
- android:layout_marginEnd="@dimen/volume_dialog_ringer_drawer_diff_end_margin"
android:layout_marginBottom="@dimen/volume_dialog_components_spacing"
+ android:clipChildren="false"
app:layout_constraintBottom_toTopOf="@id/volume_dialog_main_slider_container"
app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintHeight_default="spread"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintWidth_default="spread">
+
+ <include layout="@layout/volume_dialog_top_section" />
+ </FrameLayout>
<include
android:id="@+id/volume_dialog_main_slider_container"
layout="@layout/volume_dialog_slider" />
- <ImageButton
- android:id="@+id/volume_dialog_settings"
- android:layout_width="@dimen/volume_dialog_button_size"
- android:layout_height="@dimen/volume_dialog_button_size"
+ <FrameLayout
+ android:id="@+id/volume_dialog_bottom_section_container"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
android:layout_marginTop="@dimen/volume_dialog_components_spacing"
- android:background="@drawable/ripple_drawable_20dp"
- android:contentDescription="@string/accessibility_volume_settings"
- android:scaleType="centerInside"
- android:soundEffectsEnabled="false"
- android:tint="@androidprv:color/materialColorPrimary"
+ android:clipChildren="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+ app:layout_constraintHeight_default="wrap"
app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
app:layout_constraintTop_toBottomOf="@id/volume_dialog_main_slider_container"
- app:layout_constraintVertical_bias="0" />
+ app:layout_constraintVertical_bias="0"
+ app:layout_constraintWidth_default="wrap">
+
+ <include layout="@layout/volume_dialog_bottom_section" />
+ </FrameLayout>
<LinearLayout
android:id="@+id/volume_dialog_floating_sliders_container"
diff --git a/packages/SystemUI/res/layout/volume_dialog_bottom_section.xml b/packages/SystemUI/res/layout/volume_dialog_bottom_section.xml
new file mode 100644
index 000000000000..b94c430e011c
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_dialog_bottom_section.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/volume_dialog_settings"
+ android:layout_width="@dimen/volume_dialog_button_size"
+ android:layout_height="@dimen/volume_dialog_button_size"
+ android:layout_gravity="center"
+ android:background="@drawable/ripple_drawable_20dp"
+ android:contentDescription="@string/accessibility_volume_settings"
+ android:scaleType="centerInside"
+ android:soundEffectsEnabled="false"
+ android:tint="@androidprv:color/materialColorPrimary" /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_dialog_top_section.xml
index 8f51dbca2774..4fc20e218c5e 100644
--- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_top_section.xml
@@ -23,16 +23,17 @@
android:clipToPadding="false"
android:gravity="center"
android:layoutDirection="ltr"
+ android:paddingEnd="@dimen/volume_dialog_ringer_drawer_diff_end_margin"
app:layoutDescription="@xml/volume_dialog_ringer_drawer_motion_scene">
<View
android:id="@+id/ringer_buttons_background"
android:layout_width="@dimen/volume_dialog_width"
android:layout_height="0dp"
- android:visibility="gone"
android:layout_marginTop="@dimen/volume_dialog_background_vertical_margin"
android:layout_marginBottom="@dimen/volume_dialog_background_vertical_margin"
- android:background="@drawable/volume_dialog_ringer_background" />
+ android:background="@drawable/volume_dialog_ringer_background"
+ android:visibility="gone" />
<!-- add ringer buttons here -->
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml b/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml
index 0efbc6d651dc..c7e0f7d337c0 100644
--- a/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml
+++ b/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml
@@ -67,7 +67,7 @@
android:layout_width="@dimen/volume_ringer_drawer_icon_size"
android:layout_height="@dimen/volume_ringer_drawer_icon_size"
android:layout_gravity="center"
- android:src="@drawable/ic_volume_ringer_vibrate"
+ android:src="@drawable/ic_legacy_volume_ringer_vibrate"
android:tint="?android:attr/textColorPrimary" />
</FrameLayout>
@@ -85,7 +85,7 @@
android:layout_width="@dimen/volume_ringer_drawer_icon_size"
android:layout_height="@dimen/volume_ringer_drawer_icon_size"
android:layout_gravity="center"
- android:src="@drawable/ic_speaker_mute"
+ android:src="@drawable/ic_legacy_speaker_mute"
android:tint="?android:attr/textColorPrimary" />
</FrameLayout>
@@ -103,7 +103,7 @@
android:layout_width="@dimen/volume_ringer_drawer_icon_size"
android:layout_height="@dimen/volume_ringer_drawer_icon_size"
android:layout_gravity="center"
- android:src="@drawable/ic_speaker_on"
+ android:src="@drawable/ic_legacy_speaker_on"
android:tint="?android:attr/textColorPrimary" />
</FrameLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index e1ad98fe6aab..b8b69b6ea992 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterypersentasie is onbekend."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Gekoppel aan <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Gekoppel aan <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Vou groep uit."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Maak app oop."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Nie gekoppel nie."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Swerwing"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Af"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Verken sentrummodus"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Kry toegang tot jou gunstelinglegstukke en -skermbeskermers terwyl jy laai."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Kom ons begin"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Wys jou gunstelingsluimerskerms tydens die laaiproses"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aftrekkieslys"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Word aan die bokant van gesprekskennisgewings en as \'n profielfoto op sluitskerm gewys, verskyn as \'n borrel, onderbreek Moenie Steur Nie"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekskenmerke nie"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Terugvoer"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Maak toe"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Moenie weer wys nie"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hierdie kennisgewings kan nie gewysig word nie."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om oop te maak"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Stawing word vereis. Raak die vingerafdruksensor om te staaf."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Oproep aan die gang"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Nog besig"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Gekoppel"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tydelik gekoppel"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Voubare toestel word ontvou"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Voubare toestel word omgekeer"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Voorste skerm is aangeskakel"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gevou"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"oopgevou"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index feee18ff7219..c89ea75ad4cd 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"የባትሪ መቶኛ አይታወቅም።"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ከ<xliff:g id="BLUETOOTH">%s</xliff:g> ጋር ተገናኝቷል።"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"ከ<xliff:g id="CAST">%s</xliff:g> ጋር ተገናኝቷል።"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"ቡድንን ዘርጋ።"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"መተግበሪያ ክፈት።"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"አልተገናኘም።"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"በማዛወር ላይ"</string>
<string name="cell_data_off" msgid="4886198950247099526">"ጠፍቷል"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"የመገናኛ ሁነታን ያስሱ"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ኃይል በሚሞሉበት ወቅት የእርስዎን ተወዳጅ ምግብሮች እና ማያ ገፅ ቆጣቢዎችን ይድረሱ።"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"እንሂድ"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"ኃይል በሚሞሉበት ጊዜ ተወዳጅ የገፀ ማያ አሳራፊዎችዎን ያሳዩ"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ወደታች ተጎታች ምናሌ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"በውይይት ማሳወቂያዎች አናት ላይ እና በማያ ገፅ መቆለፊያ ላይ እንደ መገለጫ ምስል ይታያል፣ እንደ አረፋ ሆኖ ይታያል፣ አትረብሽን ያቋርጣል"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ቅድሚያ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> የውይይት ባህሪያትን አይደግፍም"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ግብረመልስ"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"አሰናብት"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ዳግም አታሳይ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"እነዚህ ማሳወቂያዎች ሊሻሻሉ አይችሉም።"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ለመክፈት የጣት አሻራ ይጠቀሙ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ማረጋገጥ ያስፈልጋል። ለማረጋገጥ የጣት አሻራ ዳሳሹን ይንኩ።"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"እየተካሄደ ያለ ጥሪ"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"በመካሄድ ላይ ያለ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"የተንቀሳቃሽ ስልክ ውሂብ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ተገናኝቷል"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"በጊዜያዊነት ተገናኝቷል"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"መታጠፍ የሚችል መሣሪያ እየተዘረጋ ነው"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"መታጠፍ የሚችል መሣሪያ እየተገለበጠ ነው"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"የፊት ለፊት ማያ ገፅ በርቷል"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"የታጠፈ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"የተዘረጋ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 31bbbb63f7ef..962f1c954a31 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"نسبة شحن البطارية غير معروفة."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"متصل بـ <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"تم الاتصال بـ <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"سيتم توسيع المجموعة."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"سيتم فتح التطبيق."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"غير متصل."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"التجوال"</string>
<string name="cell_data_off" msgid="4886198950247099526">"غير مفعّلة"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"التعرُّف على \"وضع الإرساء\""</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"يمكنك الاطّلاع على التطبيقات المصغّرة وشاشات الاستراحة المفضَّلة لديك أثناء شحن الجهاز."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"لنبدأ"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"سيتم عرض شاشات الاستراحة المفضَّلة أثناء شحن الجهاز"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تبديل المستخدم"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"القائمة المنسدلة"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"تظهر في أعلى إشعارات المحادثات وكصورة ملف شخصي على شاشة القفل وتظهر على شكل فقاعة لمقاطعة ميزة \"عدم الإزعاج\"."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"الأولوية"</string>
<string name="no_shortcut" msgid="8257177117568230126">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> ميزات المحادثات."</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"الملاحظات"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"إغلاق"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"عدم الإظهار مرة أخرى"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"يمكنك استخدام بصمة الإصبع للفتح"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"المصادقة مطلوبة. المس مستشعر بصمات الإصبع للمصادقة."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"مكالمة جارية"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"مستمر"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"بيانات الجوّال"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"متصلة بالإنترنت"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"متصلة مؤقتًا"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"جهاز قابل للطي يجري فتحه"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"جهاز قابل للطي يجري قلبه"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"تم تفعيل الشاشة الأمامية"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"مطوي"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"غير مطوي"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"‫%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 7d7e4f759bb7..b88e9e97fae1 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়, এটা বাবল হিচাপে দেখা পোৱা যায়, অসুবিধা নিদিব ম’ডত ব্যাঘাত জন্মায়"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপৰ সুবিধাসমূহ সমৰ্থন নকৰে"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"মতামত"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"অগ্ৰাহ্য কৰক"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"পুনৰাই নেদেখুৱাব"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
@@ -1395,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"জপাব পৰা ডিভাইচৰ জাপ খুলি থকা হৈছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"জপাব পৰা ডিভাইচৰ ওলোটাই থকা হৈছে"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"সন্মুখৰ স্ক্ৰীনখন অন কৰা হৈছে"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফ’ল্ড কৰা"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"আনফ’ল্ড কৰা"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 2551d9cfafa0..e629969acd10 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareyanın faizi naməlumdur."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> üzərindən qoşuldu."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> cihazına qoşulub."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Qrupu genişləndirin."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Tətbiqi açın."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Qoşulu deyil."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Rouminq"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Deaktiv"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Hab rejimini araşdırın"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Şarj edərkən sevimli vidcet və ekran qoruyucularınıza daxil olun."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Başlayaq"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Şarj edilərkən sevimli ekran qoruyucularınızı göstərin"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aşağı çəkilən menyu"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Söhbət bildirişlərinin yuxarısında və kilid ekranında profil şəkli kimi göstərilir, baloncuq kimi görünür, Narahat Etməyin rejimini kəsir"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbət funksiyalarını dəstəkləmir"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Rəy"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Rədd edin"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Yenidən göstərməyin"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmaq üçün barmaq izindən istifadə edin"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Doğrulanma tələb olunur. Doğrulamaq üçün barmaq izi sensoruna toxunun."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Davam edən zəng"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Davam edir"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Qoşulub"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Müvəqqəti qoşulub"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Qatlana bilən cihaz açılır"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Qatlana bilən cihaz fırladılır"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ön ekran aktiv edildi"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"qatlanmış"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"açıq"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index b01d83736dc0..1970144f74c6 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -109,14 +109,14 @@
<string name="screenrecord_title" msgid="4257171601439507792">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađujemo video snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obaveštenje o sesiji snimanja ekrana je aktivno"</string>
- <string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Želite da snimite ekran?"</string>
- <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Snimi jednu aplikaciju"</string>
+ <string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Želite da snimate ekran?"</string>
+ <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Snimaj jednu aplikaciju"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="4882406311415082016">"Snimi ovaj ekran"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="4169494703993148253">"Snimi %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Kada snimate ceo ekran, snima se sve što je na njemu. Zato pazite na lozinke, informacije o plaćanju, poruke, slike, audio i video sadržaj."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Kada snimate aplikaciju, snima se sav sadržaj koji se prikazuje ili pušta u njoj. Zato pazite na lozinke, informacije o plaćanju, poruke, slike, audio i video sadržaj."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Snimi ekran"</string>
- <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Odaberite aplikaciju koju želite da snimite"</string>
+ <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Odaberite aplikaciju za snimanje"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Snimaj zvuk"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk uređaja"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk sa uređaja, na primer, muzika, pozivi i melodije zvona"</string>
@@ -573,7 +573,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kada delite aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vidi sav sadržaj koji se prikazuje ili pušta u njoj. Zato pazite na lozinke, informacije o plaćanju, poruke, slike, audio i video sadržaj."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Deli ekran"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućila ovu opciju"</string>
- <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Odaberite aplikaciju koju želite da delite"</string>
+ <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Odaberite aplikaciju za deljenje"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Želite da prebacite ekran?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Prebaci jednu aplikaciju"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Prebaci ceo ekran"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu, pojavljuje se kao oblačić, prekida režim Ne uznemiravaj"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije konverzacije"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Povratne informacije"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Odbaci"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne prikazuj ponovo"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Uređaj na preklop se otvara"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Uređaj na preklop se obrće"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Prednji ekran je uključen"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Prevucite da biste koristili unutrašnji ekran"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 8f1af5f6e944..afbac9f8be09 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З’яўляецца ўверсе раздзела размоў як усплывальнае апавяшчэнне, якое перарывае рэжым \"Не турбаваць\" і паказвае на экране блакіроўкі відарыс профілю"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Прыярытэт"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае функцыі размовы"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Водгук"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Закрыць"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Больш не паказваць"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складная прылада ў раскладзеным выглядзе"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перавернутая складная прылада"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Пярэдні экран уключаны"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Правядзіце пальцам, каб выкарыстоўваць унутраны экран"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складзена"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"раскладзена"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 353815293907..77542de3bec9 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентът на батерията е неизвестен."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Има връзка с <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Установена е връзка с/ъс <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Разгъване на групата."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Отваряне на приложението."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Няма връзка."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Изключени"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Разглеждане на режима „Контролен център“"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Използвайте любимите си приспособления и скрийнсейвъри по време на зареждане."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Начало"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Показване на любимите ви скрийнсейвъри при зареждане"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Превключване между потребителите"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падащо меню"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Показва се в горната част на известията за разговори и като снимка на потребителския профил на заключения екран, изглежда като балонче, прекъсва режима „Не безпокойте“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа функциите за разговор"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Отзиви"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Отхвърляне"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Да не се показва отново"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Тези известия не могат да бъдат променяни."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Използвайте отпечатък за отваряне"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Изисква се удостоверяване на самоличността. За целта докоснете сензора за отпечатъци."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Текущо обаждане"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Текуща активност"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни данни"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Свързано"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Установена е временна връзка"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Разгъване на сгъваемо устройство"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Обръщане на сгъваемо устройство"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Предният екран е включен"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 4d885942e779..6bd1e0c0fc71 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ব্যাটারি কত শতাংশ আছে তা জানা যায়নি।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>এ সংযুক্ত হয়ে আছে।"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> এর সাথে সংযুক্ত৷"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"গ্রুপ বড় করুন।"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"অ্যাপ্লিকেশন খুলুন।"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"সংযুক্ত নয়৷"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"রোমিং"</string>
<string name="cell_data_off" msgid="4886198950247099526">"বন্ধ"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"হাব মোড ঘুরে দেখুন"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"চার্জ করার সময় আপনার পছন্দের উইজেট এবং স্ক্রিন সেভার অ্যাক্সেস করুন।"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"শুরু করা যাক"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"চার্জিংয়ের সময় আপনার পছন্দের স্ক্রিন সেভার দেখুন"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুলডাউন মেনু"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয়, বাবল হিসেবেও এটি দেখা যায় এবং এর ফলে \'বিরক্ত করবে না\' মোডে কাজ করতে অসুবিধা হয়"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ কথোপকথন ফিচার কাজ করে না"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"মতামত"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"বাতিল করুন"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"আর দেখতে চাই না"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলতে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"যাচাইকরণ করতে হবে। যাচাইকরণ করতে আঙুলের ছাপের সেন্সরে টাচ করুন।"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"চালু থাকা কল"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"চলছে"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"মোবাইল ডেটা"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"কানেক্ট করা আছে"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"সাময়িকভাবে কানেক্ট করা হয়েছে"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ফোল্ড করা যায় এমন ডিভাইস খোলা হচ্ছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ফোল্ড করা যায় এমন ডিভাইস উল্টানো হচ্ছে"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ফ্রন্ট স্ক্রিন চালু আছে"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফোল্ড করা রয়েছে"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ফোল্ড করা নেই"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 9e86aa96bab5..4ccc38ad8572 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -250,8 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak napunjenosti baterije nije poznat"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezan na <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Povezan na <xliff:g id="CAST">%s</xliff:g>."</string>
- <string name="accessibility_expand_group" msgid="521237935987978624">"Proširite grupu."</string>
- <string name="accessibility_open_application" msgid="1749126077501259712">"Otvorite aplikaciju."</string>
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Proširivanje grupe."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Otvaranje aplikacije."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Nije povezano."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Isključeno"</string>
@@ -541,7 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Istražite način rada središta"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Pristupajte svojim omiljenim vidžetima i čuvarima ekrana tokom punjenja."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Započnimo"</string>
- <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Prikaz vaših omiljenih čuvara zaslona tijekom punjenja"</string>
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Prikaz vaših omiljenih čuvara ekrana tokom punjenja"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se na vrhu obavještenja u razgovorima i kao slika profila na zaključanom ekranu, izgleda kao oblačić, prekida funkciju Ne ometaj"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije razgovora"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Povratne informacije"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Odbaci"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne prikazuj ponovo"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string>
@@ -1305,7 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je autentifikacija. Dodirnite senzor za otisak prsta da autentificirate."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Poziv u toku"</string>
- <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"U tijeku"</string>
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"U toku"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Prijenos podataka na mobilnoj mreži"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Privremeno povezano"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Sklopivi uređaj se rasklapa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Sklopivi uređaj se obrće"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Prednji ekran je uključen"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Kliznite za upotrebu unutarnjeg zaslona"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sklopljeno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otklopljeno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 25b236de53a0..80558a92194c 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Es desconeix el percentatge de bateria."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"S\'ha connectat a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Està connectat amb <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Desplega el grup."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Obre l\'aplicació."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Sense connexió."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Itinerància"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Desactivades"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Explora el mode Hub"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Accedeix als teus widgets i estalvis de pantalla preferits mentre es carrega."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Som-hi"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Mostra els teus estalvis de pantalla preferits durant la càrrega"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
@@ -573,7 +570,7 @@
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Quan comparteixes tota la pantalla, qualsevol cosa que es mostra en pantalla és visible a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Quan comparteixes una aplicació, qualsevol cosa que es mostra o que es reprodueix en aquesta aplicació és visible a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Quan comparteixes una aplicació, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> pot veure qualsevol cosa que s\'hi mostra o que s\'hi reprodueix. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Comparteix la pantalla"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ha desactivat aquesta opció"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Tria una aplicació per compartir"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Es mostra a la part superior de les notificacions de les converses i com a foto de perfil a la pantalla de bloqueig, apareix com una bombolla, interromp el mode No molestis"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritat"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet les funcions de converses"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Suggeriments"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Ignora"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"No ho tornis a mostrar"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilitza l\'empremta digital per obrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticació necessària. Toca el sensor d\'empremtes digitals per autenticar-te."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Trucada en curs"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"En curs"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dades mòbils"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connectat"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connexió temporal"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositiu plegable desplegant-se"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositiu plegable girant"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"La pantalla frontal està activada"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegat"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegat"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 26105c70ba2e..ee321074a250 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procento baterie není známé."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Připojeno k zařízení <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Jste připojeni k zařízení <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Rozbalit skupinu."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Otevřít aplikaci."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Nepřipojeno."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Vypnuto"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Prozkoumejte Režim centra"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Mějte po ruce oblíbené widgety a spořiče obrazovky při nabíjení."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Jdeme na to"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Během nabíjení zobrazovat oblíbené spořiče obrazovky"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbalovací nabídka"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string>
@@ -573,7 +570,7 @@
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Při sdílení celé obrazovky vidí aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vše, co se na obrazovce nachází nebo děje. Buďte proto opatrní, když jde o hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Při sdílení aplikace vidí aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vše, co se ve sdílené aplikaci nachází nebo děje. Buďte proto opatrní, když jde o hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Při sdílení aplikace vidí <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vše, co se ve sdílené aplikaci nachází nebo děje. Buďte proto opatrní, když jde o hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Sdílet obrazovku"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> tuto možnost zakázala"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Vyberte aplikaci ke sdílení"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka, má podobu bubliny a deaktivuje režim Nerušit"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritní"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> funkce konverzace nepodporuje"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Zpětná vazba"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Zavřít"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Už nezobrazovat"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"K otevření použijte otisk prstu"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Je vyžadováno ověření. Dotkněte se snímače otisků prstů."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Probíhající hovor"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Probíhá"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilní data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Připojeno"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Dočasně připojeno"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozkládání rozkládacího zařízení"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Otáčení rozkládacího zařízení"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Přední obrazovka je zapnutá"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"složené"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 2fe576f53f54..323b9d884ad5 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Vises øverst i samtalenotifikationer og som et profilbillede på låseskærmen. Vises som en boble, der afbryder Forstyr ikke"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalefunktioner"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Luk"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Vis ikke igen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse notifikationer kan ikke redigeres."</string>
@@ -1395,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldbar enhed foldes ud"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldbar enhed vendes om"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Frontskærmen er aktiveret"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"foldet"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"foldet ud"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 68f3a4101128..3c8be75f894b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -142,7 +142,7 @@
<string name="share_to_app_stop_dialog_title_generic" msgid="9079161538135843648">"Teilen beenden?"</string>
<string name="share_to_app_stop_dialog_message_entire_screen_with_host_app" msgid="522823522115375414">"Du teilst momentan deinen gesamten Bildschirm mit der App <xliff:g id="HOST_APP_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_entire_screen" msgid="5090115386271179270">"Du teilst momentan deinen gesamten Bildschirm mit einer App"</string>
- <string name="share_to_app_stop_dialog_message_single_app_specific" msgid="5923772039347985172">"Du teilst momentan die App <xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>"</string>
+ <string name="share_to_app_stop_dialog_message_single_app_specific" msgid="5923772039347985172">"Du teilst momentan <xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_single_app_generic" msgid="6681016774654578261">"Du teilst momentan Inhalte einer App"</string>
<string name="share_to_app_stop_dialog_message_generic" msgid="7622174291691249392">"Du teilst momentan Inhalte mit einer App"</string>
<string name="share_to_app_stop_dialog_button" msgid="6334056916284230217">"Freigabe beenden"</string>
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akkustand unbekannt."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Mit <xliff:g id="BLUETOOTH">%s</xliff:g> verbunden"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Verbunden mit <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Gruppe erweitern."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Anwendung öffnen."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Nicht verbunden"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Aus"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Hub-Modus entdecken"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Du kannst während des Ladevorgangs auf deine bevorzugten Widgets und Bildschirmschoner zugreifen."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Los gehts"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Beim Laden deine bevorzugten Bildschirmschoner anzeigen"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Pull-down-Menü"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wird oben im Bereich „Unterhaltungen“ sowie als Profilbild auf dem Sperrbildschirm angezeigt, erscheint als Bubble, unterbricht „Bitte nicht stören“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorität"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine Funktionen für Unterhaltungen"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Schließen"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Nicht mehr anzeigen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Mit Fingerabdruck öffnen"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentifizierung erforderlich. Tippe dazu einfach auf den Fingerabdrucksensor."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Aktiver Anruf"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Aktiv"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile Daten"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Verbunden"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Vorübergehend verbunden"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Faltbares Gerät wird geöffnet"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Faltbares Gerät wird umgeklappt"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Frontdisplay aktiviert"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zugeklappt"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aufgeklappt"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 412e3156f6c8..470dd2c1f353 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Άγνωστο ποσοστό μπαταρίας."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Συνδέθηκε στο <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Συνδέθηκε σε <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Αναπτύξτε την ομάδα."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Ανοίξτε την εφαρμογή."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Μη συνδεδεμένο"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Περιαγωγή"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Ανενεργά"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Εξερεύνηση της λειτουργίας Hub"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Αποκτήστε πρόσβαση στα αγαπημένα σας γραφικά στοιχεία και τις προφυλάξεις οθόνης κατά τη φόρτιση."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Ας ξεκινήσουμε"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Εμφάνιση αγαπημένων προφυλάξεων οθόνης κατά τη φόρτιση"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"αναπτυσσόμενο μενού"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Εμφανίζεται στην κορυφή των ειδοποιήσεων συζήτησης και ως φωτογραφία προφίλ στην οθόνη κλειδώματος, εμφανίζεται ως συννεφάκι, διακόπτει τη λειτουργία Μην ενοχλείτε"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Προτεραιότητα"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει τις λειτουργίες συζήτησης"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Σχόλια"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Παράβλεψη"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Να μην εμφανιστεί ξανά"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Χρήση δακτυλικού αποτυπώματος για άνοιγμα"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Απαιτείται έλεγχος ταυτότητας. Αγγίξτε τον αισθητήρα δακτυλικών αποτυπωμάτων για έλεγχο ταυτότητας."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Κλήση σε εξέλιξη"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Σε εξέλιξη"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Δεδομένα κινητής τηλεφωνίας"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Συνδέθηκε"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Προσωρινή σύνδεση"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Αναδιπλούμενη συσκευή που ξεδιπλώνει"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Αναδιπλούμενη συσκευή που διπλώνει"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Η μπροστινή οθόνη ενεργοποιήθηκε"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"διπλωμένη"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ξεδιπλωμένη"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index d5c5666d6983..0c161a7493f5 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Expand group."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Open application."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Not connected."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Off"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Explore Hub Mode"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Access your favourite widgets and screen savers while charging."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Let\'s go"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Show your favourite screensavers while charging"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Dismiss"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Don\'t show again"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Ongoing call"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Ongoing"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Temporarily connected"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index b3010e2b7d1a..3a7440bceaa0 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Dismiss"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Don\'t show again"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Slide to use inner screen"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index d5c5666d6983..0c161a7493f5 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Expand group."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Open application."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Not connected."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Off"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Explore Hub Mode"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Access your favourite widgets and screen savers while charging."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Let\'s go"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Show your favourite screensavers while charging"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Dismiss"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Don\'t show again"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Ongoing call"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Ongoing"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Temporarily connected"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index d5c5666d6983..0c161a7493f5 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Expand group."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Open application."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Not connected."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Off"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Explore Hub Mode"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Access your favourite widgets and screen savers while charging."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Let\'s go"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Show your favourite screensavers while charging"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Dismiss"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Don\'t show again"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Ongoing call"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Ongoing"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Temporarily connected"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 966c9f36cf3b..dd8f735197b8 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece en forma de burbuja y como foto de perfil en la parte superior de las notificaciones de conversación, en la pantalla de bloqueo, y detiene el modo No interrumpir"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaria"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Comentarios"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Descartar"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"No volver a mostrar"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string>
@@ -963,8 +962,8 @@
<string name="right_keycode" msgid="2480715509844798438">"Clave de código derecho"</string>
<string name="left_icon" msgid="5036278531966897006">"Ícono izquierdo"</string>
<string name="right_icon" msgid="1103955040645237425">"Ícono derecho"</string>
- <string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantén presionada la tarjeta y arrástrala para agregarla"</string>
- <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mantén presionada la tarjeta y arrástrala para reorganizarla"</string>
+ <string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantén presionada una tarjeta y arrástrala para agregarla"</string>
+ <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Mantén presionada una tarjeta y arrástrala para reubicarla"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arrastra aquí para quitar"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Necesitas al menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tarjetas"</string>
<string name="qs_edit" msgid="5583565172803472437">"Editar"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable siendo desplegado"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable siendo girado"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Pantalla frontal activada"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Desliza para usar la pantalla interior"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3c052beeb2b8..a2fcc5c75e1e 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentaje de batería desconocido."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Mostrar grupo."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir aplicación."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"No conectado."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Desactivados"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Descubre el modo Base"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Accede a tus widgets y salvapantallas favoritos mientras se carga."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Vamos allá"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Muestra tus salvapantallas favoritos mientras se carga"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Se muestra encima de las notificaciones de conversaciones y como imagen de perfil en la pantalla de bloqueo, aparece como burbuja e interrumpe el modo No molestar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Comentarios"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Cerrar"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"No volver a mostrar"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella digital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticación obligatoria. Toca el sensor de huellas digitales para autenticarte."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Llamada en curso"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"En curso"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectada temporalmente"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable desplegándose"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable mostrado desde varios ángulos"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Pantalla frontal encendida"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index defaa77a0935..bca749190858 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -133,7 +133,7 @@
<string name="screenrecord_save_error" msgid="5862648532560118815">"Viga ekraanisalvestise salvestamisel"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Viga ekraanikuva salvestamise alustamisel"</string>
<string name="screenrecord_stop_dialog_title" msgid="8716193661764511095">"Kas peatada salvestamine?"</string>
- <string name="screenrecord_stop_dialog_message" msgid="6262768207331626817">"Salvestate praegu kogu oma ekraanikuva"</string>
+ <string name="screenrecord_stop_dialog_message" msgid="6262768207331626817">"Salvestate praegu kogu oma ekraanikuva."</string>
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5995770227684523244">"Salvestate praegu rakendust <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="screenrecord_stop_dialog_button" msgid="2883812564938194350">"Peata salvestamine"</string>
<string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Ekraani jagamine"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Kuvatakse mullina vestluste märguannete ülaosas ja profiilipildina lukustuskuval ning katkestab režiimi Mitte segada"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteetne"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestlusfunktsioone"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Tagasiside"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Loobu"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ära enam näita"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Neid märguandeid ei saa muuta."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Volditava seadme lahtivoltimine"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Volditava seadme ümberpööramine"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Esiekraan on sisse lülitatud"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Lohistamine sisemisele ekraanile"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kokku volditud"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"lahti volditud"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 02da5a1619d2..f447dc6e6c48 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Bateriaren ehunekoa ezezaguna da."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> gailura konektatuta."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Hona konektatuta: <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Zabaldu taldea."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Ireki aplikazioa."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Konektatu gabe."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Ibiltaritza"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Desaktibatuta"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Arakatu kontrol-zentro modua"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Erabili gogoko dituzun widgetak eta pantaila-babesleak gailua kargatu bitartean."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Has gaitezen"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Bistaratu gogoko pantaila-babesleak kargatu bitartean"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"zabaldu menua"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string>
@@ -576,7 +573,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Aplikazio bat partekatzen ari zarenean, aplikazio horretan agertzen den edo bertan erreproduzitzen ari den guztia ikusi dezake <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Partekatu pantaila"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak aukera desgaitu du"</string>
- <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Aukeratu zer aplikazio partekatu nahi duzun"</string>
+ <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Aukeratu zein aplikazio partekatu nahi duzun"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Pantaila igorri nahi duzu?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Igorri aplikazio bat"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Igorri pantaila osoa"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Elkarrizketen jakinarazpenen goialdean eta profileko argazki gisa agertzen da pantaila blokeatuan, burbuila batean, eta ez molestatzeko modua eteten du"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Lehentasuna"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez ditu onartzen elkarrizketetarako eginbideak"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Iritzia"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Baztertu"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ez erakutsi berriro"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Erabili hatz-marka irekitzeko"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentifikazioa behar da. Autentifikatzeko, ukitu hatz-marken sentsorea."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Deia abian"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Abian"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datu-konexioa"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Konektatuta"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Aldi baterako konektatuta"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Gailu tolesgarria zabaltzen"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Gailu tolesgarria biratzen"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Aurreko pantaila piztuta dago"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"tolestuta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tolestu gabe"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 52538971217e..800bf785c339 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"در بالای اعلان‌های مکالمه و به‌صورت عکس نمایه در صفحه قفل نشان داده می‌شود، به‌صورت حبابک ظاهر می‌شود، در حالت «مزاحم نشوید» وقفه ایجاد می‌کند"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"اولویت"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ویژگی‌های مکالمه پشتیبانی نمی‌کند"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"بازخورد"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"بستن"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"دیگر نشان داده نشود"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"این اعلان‌ها قابل اصلاح نیستند."</string>
@@ -921,7 +920,7 @@
<string name="group_accessibility_toggle_bounce_keys" msgid="4183584952493519179">"تغییر وضعیت کلیدهای ضدتکرار"</string>
<string name="group_accessibility_toggle_mouse_keys" msgid="534757719357514361">"تغییر وضعیت کلیدهای موشواره"</string>
<string name="group_accessibility_toggle_sticky_keys" msgid="7722214637652104184">"تغییر وضعیت کلیدهای چسبان"</string>
- <string name="group_accessibility_toggle_slow_keys" msgid="8569881436531795062">"تغییر وضعیت کلیدهای آهسته"</string>
+ <string name="group_accessibility_toggle_slow_keys" msgid="8569881436531795062">"تغییر وضعیت کلیدهای تأخیری"</string>
<string name="group_accessibility_toggle_voice_access" msgid="5436708239015479017">"تغییر وضعیت «دسترسی صوتی»"</string>
<string name="group_accessibility_toggle_talkback" msgid="5017967056006325713">"‏روشن/خاموش کردن TalkBack"</string>
<string name="group_accessibility_toggle_magnification" msgid="3892267763383743128">"روشن/خاموش کردن درشت‌نمایی"</string>
@@ -1320,7 +1319,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"درحال جستجوی شبکه…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"اتصال به شبکه برقرار نشد"</string>
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‏فعلاً Wi-Fi به‌طور خودکار متصل نمی‌شود"</string>
- <string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"دیدن همه"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"برای تغییر شبکه، اترنت را قطع کنید"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"‏برای بهبود تجربه استفاده از دستگاه، برنامه‌ها و سرویس‌ها همچنان می‌توانند در هر زمانی شبکه‌های Wi-Fi را اسکن کنند؛ حتی وقتی که Wi-Fi خاموش باشد. می‌توانید این مورد را در تنظیمات اسکن کردن Wi‑Fi تغییر دهید. "<annotation id="link">"تغییر"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"خاموش کردن حالت هواپیما"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"دستگاه تاشو درحال باز شدن"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"دستگاه تاشو درحال چرخش به اطراف"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"صفحه‌نمایش جلو روشن شد"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"برای استفاده از صفحه‌نمایش داخلی، بلغزانید"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"تاشده"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"تانشده"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 1bd952eeff9d..fdf18a3c77e2 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -252,10 +252,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akun varaustaso ei tiedossa."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Yhteys: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Yhdistetty kohteeseen <xliff:g id="CAST">%s</xliff:g>"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Laajenna ryhmä."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Avaa sovellus."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Ei yhteyttä."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Pois päältä"</string>
@@ -545,8 +543,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Tutustu hubitilaan"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Käytä suosikkiwidgetejä ja -näytönsäästäjiä latauksen aikana."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Aloitetaan"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Näytä suosikkinäytönsäästäjiä latauksen aikana"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"alasvetovalikko"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
@@ -809,8 +806,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Näkyy keskusteluilmoitusten yläosassa ja profiilikuvana lukitusnäytöllä, näkyy kuplana, keskeyttää Älä häiritse ‑tilan"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskusteluominaisuuksia"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Palaute"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Hylkää"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Älä näytä uudelleen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string>
@@ -1310,8 +1306,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Avaa sormenjäljellä"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Todennus vaaditaan. Todenna koskettamalla sormenjälkitunnistinta."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Käynnissä oleva puhelu"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Käynnissä"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilidata"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Yhdistetty"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Väliaikaisesti yhdistetty"</string>
@@ -1401,6 +1396,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Taitettava laite taitetaan"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Taitettava laite käännetään ympäri"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Etunäyttö päällä"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"taitettu"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"taittamaton"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 6360a12a4176..dde9b64f661b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la pile inconnu."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connecté à <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Développer le groupe."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Ouvrir l\'appli."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Non connecté"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Itinérance"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Désactivé"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Explorer le mode Console"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Accéder à vos widgets et écrans de veille préférés pendant le chargement."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Allons-y"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Affichez vos écrans de veille préférés pendant le chargement"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applis et les données de cette session seront supprimées."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"S\'affiche dans le haut des notifications de conversation et comme photo de profil à l\'écran de verrouillage, s\'affiche comme bulle, interrompt le mode Ne pas déranger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les fonctionnalités de conversation"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Commentaires"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Fermer"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne plus afficher"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Servez-vous de votre empreinte digitale pour ouvrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Touchez le capteur d\'empreintes digitales pour vous authentifier."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Appel en cours"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"En cours"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Données cellulaires"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connexion active"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connectée temporairement"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable en cours de dépliage"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable en train d\'être retourné"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Écran avant activé"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 6d9760c48044..53dbfea51363 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -114,7 +114,7 @@
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="4882406311415082016">"Enregistrer cet écran"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="4169494703993148253">"Enregistrer %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Lorsque vous enregistrez l\'intégralité de votre écran, tout ce qui s\'y affiche est enregistré. Faites donc attention aux éléments tels que les mots de passe, les détails de mode de paiement, les messages, les photos, et les contenus audio et vidéo."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Lorsque vous enregistrez une appli, tout ce qui est affiché ou lu dans celle-ci est enregistré. Faites donc attention aux éléments tels que les mots de passe, détails de mode de paiement, messages, photos et contenus audio et vidéo."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Lorsque vous enregistrez une appli, tout ce qui est affiché ou lu dans celle-ci est enregistré. Faites donc preuve de vigilance concernant les mots de passe, les infos sur le mode de paiement, les messages, les photos, et les contenus audio et vidéo."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Enregistrer l\'écran"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Choisir l\'appli à enregistrer"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Enregistrer l\'audio"</string>
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la batterie inconnu."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Connecté à <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Développer le groupe."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Ouvrir l\'application."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Non connecté"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Itinérance"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Désactivées"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Découvrir le mode Hub"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Accédez à vos widgets et économiseurs d\'écran préférés lorsque l\'appareil est en charge."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"C\'est parti"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Afficher vos économiseurs d\'écran préférés pendant la recharge"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"S\'affiche en haut des notifications de conversation et en tant que photo de profil sur l\'écran de verrouillage, apparaît sous forme de bulle, interrompt le mode Ne pas déranger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les fonctionnalités de conversation"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Commentaires"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Ignorer"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne plus afficher"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilisez votre empreinte pour ouvrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Appuyez sur le lecteur d\'empreintes digitales pour vous authentifier."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Appel en cours"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"En cours"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Données mobiles"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connecté"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connexion temporaire"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable qui est déplié"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable qui est retourné"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Écran avant activé"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 3195ff506213..03ec2b0ad817 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Móstrase na parte superior das notificacións das conversas e como imaxe do perfil na pantalla de bloqueo, aparece como unha burbulla e interrompe o modo Non molestar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite funcións de conversa"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Comentarios"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Pechar"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Non volver mostrar"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string>
@@ -1395,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pregable abríndose"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pregable xirando"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Activouse a pantalla dianteira"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dispositivo pregado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dispositivo despregado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 7ad58e97ab7e..0c27927e2662 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"બૅટરીની ટકાવારી અજાણ છે."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> થી કનેક્ટ થયાં."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> થી કનેક્ટ કરેલ."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"ગ્રૂપને મોટું કરો."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"ઍપ્લિકેશન ખોલો."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"કનેક્ટ થયેલું નથી."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"રોમિંગ"</string>
<string name="cell_data_off" msgid="4886198950247099526">"બંધ કરો"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"હબ મોડ શોધખોળ કરો"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ચાર્જ કરતી વખતે તમારા મનપસંદ વિજેટ અને સ્ક્રીન સેવર ઍક્સેસ કરો."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"ચાલો પ્રારંભ કરીએ"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"ચાર્જ વખતે તમારું મનપસંદ સ્ક્રીનસેવર બતાવો"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"પુલડાઉન મેનૂ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે, બબલ તરીકે દેખાય છે, ખલેલ પાડશો નહીં મોડમાં વિક્ષેપ ઊભો કરે છે"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"પ્રાધાન્યતા"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીતની સુવિધાઓને સપોર્ટ આપતી નથી"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"પ્રતિસાદ"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"છોડી દો"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ફરી બતાવશો નહીં"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string>
@@ -914,7 +910,7 @@
<string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"ઍપ્લિકેશનો"</string>
<string name="keyboard_shortcut_group_applications_assist" msgid="6772492350416591448">"Assistant"</string>
<string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"બ્રાઉઝર"</string>
- <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Contacts"</string>
+ <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"સંપર્કો"</string>
<string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"ઇમેઇલ"</string>
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"મ્યુઝિક"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ખોલવા માટે ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"પ્રમાણીકરણ આવશ્યક છે. પ્રમાણિત કરવા માટે ફિંગરપ્રિન્ટ સેન્સરને ટચ કરો."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"ચાલુ કૉલ"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"ચાલી રહેલી પ્રવૃત્તિ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"મોબાઇલ ડેટા"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"કનેક્ટ કરેલું"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"હંગામી રીતે કનેક્ટ કર્યું"</string>
@@ -1399,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ અનફોલ્ડ કરવામાં આવી રહ્યું છે"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ફોલ્ડ કરી શકાય એવું ડિવાઇસ ફ્લિપ કરવામાં આવી રહ્યું છે"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ફ્રન્ટ સ્ક્રીનની સુવિધા ચાલુ કરેલી છે"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"અંદરની સ્ક્રીનનો ઉપયોગ કરવા માટે સ્લાઇડ કરો"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ફોલ્ડ કરેલું"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"અનફોલ્ડ કરેલું"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index f629f221bdf5..f2daffe3f443 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -142,7 +142,7 @@
<string name="share_to_app_stop_dialog_title_generic" msgid="9079161538135843648">"क्या आपको शेयर करने की प्रोसेस बंद करनी है?"</string>
<string name="share_to_app_stop_dialog_message_entire_screen_with_host_app" msgid="522823522115375414">"फ़िलहाल, <xliff:g id="HOST_APP_NAME">%1$s</xliff:g> पर पूरी स्क्रीन शेयर की जा रही है"</string>
<string name="share_to_app_stop_dialog_message_entire_screen" msgid="5090115386271179270">"फ़िलहाल, किसी ऐप्लिकेशन पर पूरी स्क्रीन शेयर की जा रही है"</string>
- <string name="share_to_app_stop_dialog_message_single_app_specific" msgid="5923772039347985172">"फ़िलहाल, <xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g> शेयर किया जा रहा है"</string>
+ <string name="share_to_app_stop_dialog_message_single_app_specific" msgid="5923772039347985172">"फ़िलहाल, <xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g> की स्क्रीन शेयर की जा रही है"</string>
<string name="share_to_app_stop_dialog_message_single_app_generic" msgid="6681016774654578261">"फ़िलहाल, कोई ऐप्लिकेशन शेयर किया जा रहा है"</string>
<string name="share_to_app_stop_dialog_message_generic" msgid="7622174291691249392">"फ़िलहाल, ऐप्लिकेशन के साथ कुछ शेयर किया जा रहा है"</string>
<string name="share_to_app_stop_dialog_button" msgid="6334056916284230217">"शेयर करना बंद करें"</string>
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"इस बारे में जानकारी नहीं है कि अभी बैटरी कितने प्रतिशत चार्ज है."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> से कनेक्ट किया गया."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> से कनेक्ट है."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"ग्रुप को बड़ा करें."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"ऐप्लिकेशन खोलें."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"कनेक्ट नहीं है."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"रोमिंग"</string>
<string name="cell_data_off" msgid="4886198950247099526">"बंद है"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"हब मोड को एक्सप्लोर करें"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"चार्जिंग के दौरान, अपने पसंदीदा विजेट और स्क्रीन सेवर को ऐक्सेस करें."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"आइए शुरू करें"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"चार्ज करते समय अपने पसंदीदा स्क्रीन सेवर दिखाएं"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेन्यू"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सेशन के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"यह कई तरीकों से दिखती है, जैसे कि बातचीत वाली सूचनाओं में सबसे ऊपर, बबल के तौर पर, और लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर. साथ ही, यह \'परेशान न करें\' मोड को बायपास कर सकती है"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर बातचीत की सुविधाएं काम नहीं करतीं"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"सुझाव/राय दें या शिकायत करें"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"खारिज करें"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"फिर से न दिखाएं"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ये सूचनाएं नहीं बदली जा सकती हैं."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"खोलने के लिए, फ़िंगरप्रिंट का इस्तेमाल करें"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि करना ज़रूरी है. पुष्टि करने के लिए, फ़िंगरप्रिंट सेंसर को छुएं."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"पहले से जारी कॉल"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"जारी है"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट हो गया"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"इंटरनेट कनेक्शन कुछ समय के लिए है"</string>
@@ -1399,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फ़ोल्ड किया जा सकने वाला डिवाइस अनफ़ोल्ड किया जा रहा है"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फ़ोल्ड किया जा सकने वाला डिवाइस पलटा जा रहा है"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"फ़्रंट स्क्रीन चालू है"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"इनर स्क्रीन का इस्तेमाल करने के लिए स्लाइड करें"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"डिवाइस फ़ोल्ड किया गया"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"डिवाइस अनफ़ोल्ड किया गया"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1457,7 +1453,7 @@
<string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"मौजूदा ऐप्लिकेशन"</string>
<string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"सुलभता"</string>
<string name="shortcut_helper_title" msgid="8567500639300970049">"कीबोर्ड शॉर्टकट"</string>
- <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"शॉर्टकट पसंद के मुताबिक बनाएं"</string>
+ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"पसंद के मुताबिक शॉर्टकट बनाएं"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"क्या आपको शॉर्टकट हटाना है?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"क्या आपको फिर से डिफ़ॉल्ट शॉर्टकट चालू करने हैं?"</string>
<string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"यह शॉर्टकट बनाने के लिए, ऐक्शन बटन और एक या उससे ज़्यादा अन्य बटन एक साथ दबाएं"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index dd0a6c1e729e..5222e8010e81 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se pri vrhu obavijesti razgovora i kao profilna slika na zaključanom zaslonu, izgleda kao oblačić, prekida Ne uznemiravaj"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava značajke razgovora"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Povratne informacije"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Odbaci"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne prikazuj ponovo"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Te se obavijesti ne mogu izmijeniti."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rasklopljen sklopivi uređaj"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Okretanje sklopivog uređaja sa svih strana"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Prednji zaslon je uključen"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Kliznite za upotrebu unutarnjeg zaslona"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 56270b4062a9..109c52fd6e8d 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Az akkumulátor töltöttségi szintje ismeretlen."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Csatlakoztatva a következőhöz: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Csatlakozva a következőhöz: <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Csoport kibontása."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Alkalmazás megnyitása."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Nincs csatlakozva."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Ki"</string>
@@ -298,7 +296,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"A képernyő zárolva van fekvő tájolásban."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"A képernyő zárolva van álló tájolásban."</string>
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
- <string name="start_dreams" msgid="9131802557946276718">"Képernyővédő"</string>
+ <string name="start_dreams" msgid="9131802557946276718">"Képernyőkímélő"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne zavarjanak"</string>
<string name="quick_settings_modes_label" msgid="879156359479504244">"Módok"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"A Hub mód felfedezése"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Töltés közben hozzáférhet kedvenc moduljaihoz és képernyőkímélőihez."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Kezdés"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Kedvenc képernyőkímélők megjelenítése töltés közben"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"lehúzható menü"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"A beszélgetésekre vonatkozó értesítések tetején, lebegő buborékként látható, megjeleníti a profilképet a lezárási képernyőn, és megszakítja a Ne zavarjanak funkciót"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritás"</string>
<string name="no_shortcut" msgid="8257177117568230126">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> nem támogatja a beszélgetési funkciókat"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Visszajelzés"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Elvetés"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne jelenjen meg újra"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ujjlenyomat használata a megnyitáshoz"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Hitelesítés szükséges. Érintse meg az ujjlenyomat-érzékelőt a hitelesítéshez."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Hívás folyamatban"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Folyamatban van"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiladat"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Csatlakozva"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Ideiglenesen csatlakoztatva"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Összehajtható eszköz kihajtása"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Összehajtható eszköz körbeforgatása"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Előlapi képernyő bekapcsolva"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"összehajtva"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kihajtva"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index bb92212f0004..914d2cd8fd78 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Մարտկոցի լիցքի մակարդակն անհայտ է։"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Միացված է <xliff:g id="BLUETOOTH">%s</xliff:g>-ին:"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Միացված է <xliff:g id="CAST">%s</xliff:g>-ին:"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Ծավալել խումբը։"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Բացել հավելվածը։"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Միացված չէ:"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Ռոումինգ"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Անջատված է"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Բացահայտեք հանգույցի ռեժիմը"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Օգտագործեք ձեր սիրած վիջեթները և էկրանապահները, մինչ ձեր սարքը լիցքավորվում է։"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Սկսել"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Ցուցադրել էկրանապահներ լիցքավորման ժամանակ"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"իջնող ընտրացանկ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ցուցադրվում է զրույցների ծանուցումների վերևում, ինչպես նաև կողպէկրանին որպես պրոֆիլի նկար, հայտնվում է ամպիկի տեսքով, ընդհատում է «Չանհանգստացնել» ռեժիմը"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը զրույցի գործառույթներ չի աջակցում"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Կարծիք հայտնել"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Փակել"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Այլևս ցույց չտալ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Բացելու համար օգտագործեք մատնահետքը"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Պահանջվում է նույնականացում։ Դրա համար մատը հպեք մատնահետքի սկաներին։"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Ընթացիկ զանգ"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Հիմա"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Բջջային ինտերնետ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Միացած է"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Ժամանակավոր կապ"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ծալովի սարք՝ բացված վիճակում"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Ծալովի սարք՝ շրջված վիճակում"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Առջևի էկրանը միացված է"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ծալված"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"բացված"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 60f8ea7f60fa..62e347603242 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Persentase baterai tidak diketahui."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Terhubung ke <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Terhubung ke <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Meluaskan grup."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Membuka aplikasi."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Tidak terhubung."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Nonaktif"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Jelajahi mode hub"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Akses widget dan screensaver favorit Anda saat mengisi daya."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Mulai"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Tampilkan screensaver favorit saat mengisi daya"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pulldown"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data dalam sesi ini akan dihapus."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Muncul teratas di notifikasi percakapan dan sebagai foto profil di layar kunci, ditampilkan sebagai balon, menimpa mode Jangan Ganggu"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritas"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung fitur percakapan"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Masukan"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Tutup"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Jangan tampilkan lagi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Notifikasi ini tidak dapat diubah."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan sidik jari untuk membuka"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Perlu autentikasi. Sentuh sensor sidik jari untuk melakukan autentikasi."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Panggilan sedang berlangsung"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Sedang berlangsung"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Data seluler"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Terhubung"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Terhubung sementara"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Perangkat foldable sedang dibentangkan"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Perangkat foldable sedang dibalik"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Layar depan diaktifkan"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ditutup"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dibuka"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 68e395b3498d..4e486d01caa4 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Birtist efst í samtalstilkynningum og sem prófílmynd á lásskjánum. Birtist sem blaðra sem truflar „Ónáðið ekki“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Forgangur"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki samtalseiginleika"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Ábendingar"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Loka"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ekki sýna aftur"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string>
@@ -1395,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Samanbrjótanlegt tæki opnað"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Samanbrjótanlegu tæki snúið við"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Kveikt á fremri skjá"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"samanbrotið"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opið"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index c839a7b89106..786254be73c0 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -408,8 +408,8 @@
<string name="custom_trace_settings_dialog_title" msgid="2608570500144830554">"Impostazioni di traccia personalizzate"</string>
<string name="restore_default" msgid="5259420807486239755">"Ripristina predefinite"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modalità a una mano"</string>
- <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Apparecchi acustici"</string>
- <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Attivi"</string>
+ <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Protesi uditive"</string>
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Attive"</string>
<string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnessi"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Protesi uditive"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Accoppia nuovo dispositivo"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Appare in cima alle notifiche delle conversazioni, come immagine del profilo nella schermata di blocco e sotto forma di bolla, inoltre interrompe la modalità Non disturbare"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Ignora"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Non mostrare più"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pieghevole che viene aperto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pieghevole che viene capovolto"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Schermo frontale attivato"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Scorri per usare lo schermo interno"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"Piegato"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"Non piegato"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index fe5d6f3ebfed..50008854f1df 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -114,7 +114,7 @@
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="4882406311415082016">"הקלטת המסך שמוצג עכשיו"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="4169494703993148253">"‏הקלטה של %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"כשמקליטים את כל המסך, כל מה שמופיע במסך מוקלט. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"כשמקליטים אפליקציה, כל מה שרואים או מפעילים בה מוקלט. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"כשמקליטים אפליקציה, כל מה שרואים או מפעילים בה מוקלט. מומלץ להיזהר ולא לחשוף פרטים אישיים כמו סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"הקלטת המסך"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"בחירת אפליקציה להקלטה"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"הקלטת אודיו"</string>
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"אחוז טעינת הסוללה לא ידוע."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"התבצע חיבור אל <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"מחובר אל <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"הרחבת הקבוצה."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"פתיחת האפליקציה."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"אין חיבור."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"נדידה"</string>
<string name="cell_data_off" msgid="4886198950247099526">"כבוי"</string>
@@ -460,7 +458,7 @@
<string name="zen_modes_dialog_title" msgid="8854640808100096934">"מצבים"</string>
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"סיום"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"הגדרות"</string>
- <string name="zen_mode_on" msgid="9085304934016242591">"מצב מופעל"</string>
+ <string name="zen_mode_on" msgid="9085304934016242591">"מצב פעיל"</string>
<string name="zen_mode_on_with_details" msgid="7416143430557895497">"פועל • <xliff:g id="TRIGGER_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="zen_mode_off" msgid="1736604456618147306">"מצב מושבת"</string>
<string name="zen_mode_set_up" msgid="8231201163894922821">"לא הוגדר"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"‏האפשרויות במצב Hub"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"אפשר לגשת לווידג\'טים ולשומרי המסך בזמן הטעינה."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"שנתחיל?"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"בחירת שומרי המסך שיוצגו בזמן הטעינה"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"תפריט במשיכה למטה"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string>
@@ -573,10 +570,10 @@
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"כשמשתפים את כל המסך, כל מה שמופיע בו יהיה גלוי ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"כשמשתפים אפליקציה, כל מה שרואים או מפעילים בה יהיה גלוי ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"כשמשתפים אפליקציה, כל מה שרואים או מפעילים בה מופיע גם ב-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. מומלץ להיזהר ולא לחשוף פרטים אישיים כמו סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"שיתוף המסך"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> השביתה את האפשרות הזו"</string>
- <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"בחירת האפליקציה לשיתוף"</string>
+ <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"בחירת אפליקציה לשיתוף"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"‏להפעיל Cast של המסך?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"‏הפעלת Cast של אפליקציה אחת"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"‏הפעלת Cast של כל המסך"</string>
@@ -593,7 +590,7 @@
<string name="media_projection_task_switcher_action_switch" msgid="8682258717291921123">"שיתוף של האפליקציה הזו במקום"</string>
<string name="media_projection_task_switcher_action_back" msgid="5324164224147845282">"חזרה למשימה הקודמת"</string>
<string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"החלפת אפליקציה"</string>
- <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"‏האפשרות נחסמה על ידי אדמין ב-IT"</string>
+ <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"‏האפשרות נחסמה על ידי אדמין ממחלקת IT"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"צילום המסך מושבת בגלל מדיניות המכשיר"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"ניקוי הכול"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"ניהול"</string>
@@ -936,7 +933,7 @@
<string name="accessibility_long_click_tile" msgid="210472753156768705">"פתיחת ההגדרות"</string>
<string name="accessibility_status_bar_headphones" msgid="1304082414912647414">"אוזניות מחוברות"</string>
<string name="accessibility_status_bar_headset" msgid="2699275863720926104">"אוזניות מחוברות"</string>
- <string name="data_saver" msgid="3484013368530820763">"‏חוסך הנתונים (Data Saver)"</string>
+ <string name="data_saver" msgid="3484013368530820763">"חוסך הנתונים"</string>
<string name="accessibility_data_saver_on" msgid="5394743820189757731">"‏חוסך הנתונים (Data Saver) פועל"</string>
<string name="switch_bar_on" msgid="1770868129120096114">"פועל"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"כבוי"</string>
@@ -1087,7 +1084,7 @@
<string name="privacy_type_media_projection" msgid="8136723828804251547">"הקלטת המסך"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ללא שם"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string>
- <string name="font_scaling_dialog_title" msgid="6273107303850248375">"גודל גופן"</string>
+ <string name="font_scaling_dialog_title" msgid="6273107303850248375">"גודל הגופן"</string>
<string name="font_scaling_smaller" msgid="1012032217622008232">"הקטנה"</string>
<string name="font_scaling_larger" msgid="5476242157436806760">"הגדלה"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"חלון הגדלה"</string>
@@ -1308,8 +1305,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"שימוש בטביעת אצבע כדי לפתוח"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"נדרש אימות. יש לגעת בחיישן טביעות האצבע כדי לבצע אימות."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"שיחה פעילה"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"בתהליך"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"חבילת גלישה"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"מחובר"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"מחובר באופן זמני"</string>
@@ -1399,6 +1395,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"מכשיר מתקפל עובר למצב לא מקופל"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"מכשיר מתקפל עובר למצב מהופך"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"המסך הקדמי מופעל"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"מצב מקופל"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"מצב לא מקופל"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"‏%1$s‏ / %2$s"</string>
@@ -1422,7 +1420,7 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"נוכחות המשתמש זוהתה"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"צריך להגדיר את אפליקציית ברירת המחדל לפתקים ב\'הגדרות\'"</string>
<string name="install_app" msgid="5066668100199613936">"התקנת האפליקציה"</string>
- <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"מחליקים למעלה כדי להמשיך"</string>
+ <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"צריך להחליק למעלה כדי להמשיך"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"לשקף למסך חיצוני?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"המסך הפנימי שלך ישוכפל. המסך החיצוני שלך יכובה."</string>
<string name="mirror_display" msgid="2515262008898122928">"תצוגת מראה"</string>
@@ -1460,7 +1458,7 @@
<string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"התאמה אישית של מקשי הקיצור"</string>
<string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"להסיר את קיצור הדרך?"</string>
<string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"לאפס לברירת המחדל?"</string>
- <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"כדי ליצור את קיצור הדרך הזה, מקישים על מקש הפעולה ועל עוד מקש אחד או יותר ביחד"</string>
+ <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"כדי לבחור את צירוף המקשים הרצוי, מקישים בו-זמנית על מקש הפעולה ועל עוד מקש אחד או יותר"</string>
<string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"קיצור הדרך יימחק לתמיד."</string>
<string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"הפעולה הזו תמחק לתמיד את כל קיצורי הדרך שמותאמים אישית."</string>
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"חיפוש מקשי קיצור"</string>
@@ -1477,7 +1475,7 @@
<string name="shortcut_helper_key_combinations_forward_slash" msgid="1238652537199346970">"קו נטוי"</string>
<string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"נקודת האחיזה לגרירה"</string>
<string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"הגדרות המקלדת"</string>
- <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"הגדרת מקש קיצור"</string>
+ <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"הגדרת מקשי הקיצור"</string>
<string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"הסרה"</string>
<string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"כן, לאפס"</string>
<string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ביטול"</string>
diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
index d6b9bc8950af..1a5b8fbcd20d 100644
--- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
@@ -194,6 +194,6 @@
<string-array name="tile_states_notes">
<item msgid="5894333929299989301">"לא זמין"</item>
<item msgid="6419996398343291862">"מושבת"</item>
- <item msgid="5908720590832378783">"מופעל"</item>
+ <item msgid="5908720590832378783">"מצב פעיל"</item>
</string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 810fef9c3942..fd98fe822b6f 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -113,8 +113,8 @@
<string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"1 つのアプリを録画"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="4882406311415082016">"この画面の録画"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="4169494703993148253">"%s の録画"</string>
- <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"画面全体を録画すると、画面に表示されるものがすべて録画されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
- <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"アプリを録画すると、そのアプリで表示または再生される内容がすべて録画されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
+ <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"画面全体を録画すると、画面に表示されるものがすべて録画されます。パスワード、お支払い情報、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
+ <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"アプリを録画すると、そのアプリで表示または実行される内容がすべて録画されます。パスワード、お支払い情報、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"画面を録画"</string>
<string name="screenrecord_app_selector_title" msgid="3854492366333954736">"録画するアプリを選択"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"録音"</string>
@@ -558,9 +558,9 @@
<string name="user_remove_user_message" msgid="6702834122128031833">"このユーザーのアプリとデータがすべて削除されます。"</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"削除"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> で録画やキャストを開始しますか?"</string>
- <string name="media_projection_dialog_warning" msgid="1303664408388363598">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> は、録画中またはキャスト中に画面上に表示または再生される情報のすべてにアクセスできるようになります。これには、パスワード、お支払いの詳細、写真、メッセージ、音声などが含まれます。"</string>
+ <string name="media_projection_dialog_warning" msgid="1303664408388363598">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> は、録画中またはキャスト中に画面上に表示または再生される情報のすべてにアクセスできるようになります。これには、パスワード、お支払い情報、写真、メッセージ、音声などが含まれます。"</string>
<string name="media_projection_sys_service_dialog_title" msgid="3751133258891897878">"録画やキャストを開始しますか?"</string>
- <string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"この機能を提供するサービスは、録画中またはキャスト中に画面上に表示または再生される情報のすべてにアクセスできるようになります。これには、パスワード、お支払いの詳細、写真、メッセージ、音声などが含まれます。"</string>
+ <string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"この機能を提供するサービスは、録画中またはキャスト中に画面上に表示または再生される情報のすべてにアクセスできるようになります。これには、パスワード、お支払い情報、写真、メッセージ、音声などが含まれます。"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"アプリの共有または録画"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> と画面を共有しますか?"</string>
<string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"1 個のアプリを共有"</string>
@@ -569,21 +569,21 @@
<string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"画面全体を共有"</string>
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
- <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"画面全体を共有すると、画面に表示される内容が <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> にすべて公開されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"アプリを共有すると、そのアプリで表示または再生される内容が <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> にすべて公開されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"画面全体を共有すると、画面に表示される内容が <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> にすべて公開されます。パスワード、お支払い情報、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"アプリを共有すると、そのアプリで表示または再生される内容が <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> にすべて公開されます。パスワード、お支払い情報、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"画面を共有"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> がこのオプションを無効にしています"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"共有するアプリを選択"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"画面をキャストしますか?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"1 つのアプリをキャスト"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"画面全体をキャスト"</string>
- <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"画面全体をキャストすると、画面に表示される内容がすべて公開されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
- <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"アプリをキャストすると、そのアプリで表示または再生される内容がすべて公開されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
+ <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"画面全体をキャストすると、画面に表示される内容がすべて公開されます。パスワード、お支払い情報、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
+ <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"アプリをキャストすると、そのアプリで表示または再生される内容がすべて公開されます。パスワード、お支払い情報、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
<string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"画面のキャスト"</string>
<string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"キャストするアプリを選択"</string>
<string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"共有を開始しますか?"</string>
- <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"共有、録画、キャスト中は、画面に表示される内容やデバイスで再生される内容に Android がアクセスできるため、パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
- <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"アプリの共有、録画、キャスト中は、そのアプリで表示または再生される内容に Android がアクセスできるため、パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
+ <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"共有、録画、キャスト中は、画面に表示される内容やデバイスで再生される内容に Android がアクセスできるため、パスワード、お支払い情報、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
+ <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"アプリの共有、録画、キャスト中は、そのアプリで表示または再生される内容に Android がアクセスできるため、パスワード、お支払い情報、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
<string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"開始"</string>
<string name="media_projection_entry_generic_permission_dialog_continue_single_app" msgid="5920814988611877051">"次へ"</string>
<string name="media_projection_task_switcher_text" msgid="590885489897412359">"アプリを切り替えるときに共有を一時停止します"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"会話通知の一番上に表示されると同時に、ロック画面にプロフィール写真として表示されるほか、バブルとして表示され、サイレント モードが中断されます"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>は会話機能に対応していません"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"フィードバック"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"閉じる"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"次回から表示しない"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"折りたたみ式デバイスが広げられている"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"折りたたみ式デバイスがひっくり返されている"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"フロント画面が ON になりました"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"インナー ディスプレイを使用するにはスライドしてください"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折りたたんだ状態"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"広げた状態"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index a8fd410b6dff..18522da3dfb4 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ბატარეის პროცენტული მაჩვენებელი უცნობია."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"დაკავშირებულია <xliff:g id="BLUETOOTH">%s</xliff:g>-თან."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"დაკავშირებულია მოწყობილობასთან: <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"ჯგუფის გაფართოება."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"აპლიკაციის გახსნა."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"არ არის დაკავშირებული."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"როუმინგი"</string>
<string name="cell_data_off" msgid="4886198950247099526">"გამორთული"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ჰაბის რეჟიმის დათვალიერება"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"დატენის დროს შეგიძლიათ თქვენს რჩეულ ვიჯეტებზე და ეკრანმზოგებზე წვდომა."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"დავიწყოთ"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"დატენვისას თქვენი საყვარელი ეკრანმზოგის ჩვენება"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"მომხმარებლის გადართვა"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ჩამოშლადი მენიუ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"გამოჩნდება საუბრის შეტყობინებების თავში და პროფილის სურათის სახით ჩაკეტილ ეკრანზე, ჩნდება ბუშტის სახით, წყვეტს ფუნქციას „არ შემაწუხოთ“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"პრიორიტეტი"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს მიმოწერის ფუნქციების მხარდაჭერა"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"გამოხმაურება"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"დახურვა"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"აღარ მაჩვენო"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ამ შეტყობინებების შეცვლა შეუძლებელია."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"გასახსნელად გამოიყენეთ თითის ანაბეჭდი"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"საჭიროა ავტორიზაცია. ავტორიზაციისთვის შეეხეთ თითის ანაბეჭდის სენსორს."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"მიმდინარე ზარი"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"მიმდინარე"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"მობილური ინტერნეტი"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"დაკავშირებული"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"დროებით დაკავშირებული"</string>
@@ -1399,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"დასაკეცი მოწყობილობა იხსნება"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"დასაკეცი მოწყობილობა ტრიალებს"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"წინა ეკრანი ჩართულია"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"გაასრიალეთ შიდა ეკრანის გამოსაყენებლად"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"დაკეცილი"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"გაშლილი"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 16569fe52a00..83af7c8b8607 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея зарядының мөлшері белгісіз."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> қосылған."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> трансляциясына қосылды."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Топты жайыңыз."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Қолданбаны ашыңыз."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Жалғанбаған."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Өшірулі"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Хаб режимін шолу"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Зарядтау кезінде өзіңіз ұнататын виджеттер мен скринсейверлерді пайдаланыңыз."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Бастайық"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Құрылғыны зарядтау кезінде таңдаулы скринсейверлерді көрсетуге болады."</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ашылмалы мәзір"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданба мен дерек жойылады."</string>
@@ -593,7 +590,7 @@
<string name="media_projection_task_switcher_action_switch" msgid="8682258717291921123">"Орнына осы қолданбаны бөлісу"</string>
<string name="media_projection_task_switcher_action_back" msgid="5324164224147845282">"Қайта ауысу"</string>
<string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"Қолданба ауыстыру"</string>
- <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Әкімшіңіз бөгеген"</string>
+ <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Әкімшіңіз блоктаған"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Құрылғы саясатына байланысты экранды түсіру өшірілді."</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"Барлығын тазарту"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Басқару"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Әңгіме туралы хабарландырулардың жоғарғы жағында тұрады және құлыптаулы экранда профиль суреті болып көрсетіледі, қалқыма хабар түрінде шығады, Мазаламау режимін тоқтатады."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маңызды"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгіме функцияларын қолдамайды."</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Пікір"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Жабу"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Қайта көрсетілмесін"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ашу үшін саусақ ізін пайдаланыңыз."</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аутентификациядан өту қажет. Ол үшін саусақ ізін оқу сканерін түртіңіз."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Ағымдағы қоңырау"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Ағымдағы"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильдік интернет"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Жалғанды"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Уақытша байланыс орнатылды."</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Бүктемелі құрылғы ашылып жатыр."</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Бүктемелі құрылғы аударылып жатыр."</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Алдыңғы экран қосылды."</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"жабық"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ашық"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 1cf437c9e949..569ecd3d1677 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"បង្ហាញនៅខាងលើ​ការជូនដំណឹងអំពីការសន្ទនា និងជារូបភាព​កម្រង​ព័ត៌មាននៅលើអេក្រង់ចាក់សោ បង្ហាញជាពពុះ បង្អាក់មុខងារកុំ​រំខាន"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើ​មុខងារ​សន្ទនា​បានទេ"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"មតិកែលម្អ"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"ច្រានចោល"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"កុំបង្ហាញម្ដងទៀត"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាច​កែប្រែ​ការជូនដំណឹង​ទាំងនេះ​បានទេ។"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ឧបករណ៍អាច​បត់បានកំពុងត្រូវបានលា"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ឧបករណ៍អាច​បត់បានកំពុងត្រូវបានលា"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"បានបើកអេក្រង់ខាងមុខ"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"រំកិលដើម្បីប្រើអេក្រង់ខាងក្នុង"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"បត់"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"លា"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 5cfb42cf5091..5bcd986b2bad 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ಸಂಭಾಷಣೆ ಅಧಿಸೂಚನೆಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಹಾಗೂ ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವಾಗಿ ತೋರಿಸುತ್ತದೆ, ಬಬಲ್‌ನಂತೆ ಗೋಚರಿಸುತ್ತದೆ, ಅಡಚಣೆ ಮಾಡಬೇಡ ಮೋಡ್‌ಗೆ ಅಡ್ಡಿಯುಂಟುಮಾಡುತ್ತದೆ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"ಸಂವಾದ ಫೀಚರ್‌ಗಳನ್ನು <xliff:g id="APP_NAME">%1$s</xliff:g> ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ಫೀಡ್‌ಬ್ಯಾಕ್"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"ವಜಾಗೊಳಿಸಿ"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ಫೋಲ್ಡ್ ಮಾಡಬಹುದಾದ ಸಾಧನವನ್ನು ಸುತ್ತಲೂ ತಿರುಗಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ಫ್ರಂಟ್ ಸ್ಕ್ರೀನ್ ಆನ್ ಆಗಿದೆ"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"ಒಳಗಿನ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಸ್ಲೈಡ್ ಮಾಡಿ"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 78f87a2cdfa3..fd2c62e16a17 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"배터리 잔량을 알 수 없습니다."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>에 연결되었습니다."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>에 연결됨"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"그룹을 펼칩니다."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"애플리케이션을 엽니다."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"연결되지 않았습니다."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"로밍"</string>
<string name="cell_data_off" msgid="4886198950247099526">"사용 안함"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"허브 모드 살펴보기"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"충전하는 동안 즐겨 찾는 위젯과 화면 보호기에 액세스하세요."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"시작"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"충전 중에 즐겨찾는 화면 보호기 표시"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"풀다운 메뉴"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"대화 알림 상단에 표시, 잠금 화면에 프로필 사진으로 표시, 대화창으로 표시, 방해 금지 모드를 무시함"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"의견"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"닫기"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"다시 표시하지 않음"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string>
@@ -1143,7 +1139,7 @@
<string name="accessibility_floating_button_action_remove_menu" msgid="6730432848162552135">"삭제"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"전환"</string>
<string name="accessibility_floating_button_action_edit" msgid="1688227814600463987">"수정"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"기기 제어"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"컨트롤을 추가할 앱을 선택하세요"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{설정이 #개 추가되었습니다.}other{설정이 #개 추가되었습니다.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"삭제됨"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"지문으로 열기"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"인증이 필요합니다. 지문 센서를 터치하여 인증하세요."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"진행 중인 통화"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"진행 중"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"모바일 데이터"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"연결됨"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"일시적으로 연결됨"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"폴더블 기기를 펼치는 모습"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"폴더블 기기를 뒤집는 모습"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"전면 화면 켜짐"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"접은 상태"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"펼친 상태"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index bdbbf049376a..1916cbc21270 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батареянын деңгээли белгисиз."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> менен туташкан."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> менен туташты."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Топту жайып көрсөтүү."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Колдонмону ачуу."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Интернет жок."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Өчүк"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Түйүн режимин колдонуп көрүңүз"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Кубатталып жатканда жактырган виджеттериңизди жана көшөгөлөрдү колдонуңуз."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Кеттик!"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Кубаттап жатканда жактырган көшөгөлөрдү көрсөтүңүз"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Колдонуучуну которуу"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ылдый түшүүчү меню"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана аларга байланыштуу нерселер өчүрүлөт."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Cүйлөшүүлөр тууралуу билдирмелердин жогору жагында жана кулпуланган экранда профилдин сүрөтү, ошондой эле калкып чыкма билдирме түрүндө көрүнүп, \"Тынчымды алба\" режимин токтотот"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда оозеки сүйлөшкөнгө болбойт"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Пикир билдирүү"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Жабуу"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Экинчи көрсөтүлбөсүн"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Манжаңыздын изи менен ачыңыз"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аныктыкты текшерүү талап кылынат. Аныктыгын текшерүү үчүн манжа изинин сенсоруна тийип коюңуз."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Учурдагы чалуу"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Учурдагы"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилдик трафик"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Туташты"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Убактылуу туташып турат"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ачылып турган бүктөлмө түзмөк"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Оодарылып жаткан бүктөлмө түзмөк"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Маңдайкы экран күйгүзүлдү"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"бүктөлгөн"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ачылган"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 1acb34a9cccb..f61186d19e0b 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ບໍ່ຮູ້ເປີເຊັນແບັດເຕີຣີ."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ເຊື່ອມ​ຕໍ່​ຫາ <xliff:g id="BLUETOOTH">%s</xliff:g> ແລ້ວ."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"ເຊື່ອມຕໍ່ຫາ <xliff:g id="CAST">%s</xliff:g> ແລ້ວ."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"ຂະຫຍາຍກຸ່ມ."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"ເປີດແອັບພລິເຄຊັນ."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"ບໍ່ໄດ້ເຊື່ອມຕໍ່."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"ໂຣມມິງ"</string>
<string name="cell_data_off" msgid="4886198950247099526">"ປິດ"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ສຳຫຼວດໂໝດ Hub"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ເຂົ້າເຖິງວິດເຈັດ ແລະ ພາບພັກໜ້າຈໍທີ່ທ່ານມັກໃນລະຫວ່າງທີ່ສາກ."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"ມາເລີ່ມກັນເລີຍ"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"ສະແດງພາບພັກໜ້າຈໍທີ່ທ່ານມັກໃນລະຫວ່າງທີ່ສາກ"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ເມນູແບບດຶງລົງ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯ​ແລະ​ຂໍ້​ມູນ​ທັງ​ໝົດ​ໃນ​ເຊດ​ຊັນ​ນີ້​ຈະ​ຖືກ​ລຶບ​ອອກ."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ສະແດງຢູ່ເທິງສຸດຂອງການແຈ້ງເຕືອນການສົນທະນາ ແລະ ເປັນຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ, ປາກົດເປັນຟອງ, ສະແດງໃນໂໝດຫ້າມລົບກວນໄດ້"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ສຳຄັນ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບຄຸນສົມບັດການສົນທະນາ"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ຄຳຕິຊົມ"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"ປິດໄວ້"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ໃຊ້ລາຍນິ້ວມືເພື່ອເປີດ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ຕ້ອງພິສູດຢືນຢັນ. ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມືເພື່ອພິສູດຢືນຢັນ."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"ສາຍທີ່ສົນທະນາຢູ່"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"ດຳເນີນຢູ່"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ອິນເຕີເນັດມືຖື"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"ເຊື່ອມຕໍ່ແລ້ວຊົ່ວຄາວ"</string>
@@ -1399,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ອຸປະກອນທີ່ພັບໄດ້ກຳລັງກາງອອກ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ອຸປະກອນທີ່ພັກໄດ້ກຳລັງປີ້ນໄປມາ"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ເປີດໜ້າຈໍດ້ານໜ້າແລ້ວ"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"ເລື່ອນເພື່ອໃຊ້ໜ້າຈໍດ້ານໃນ"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ພັບແລ້ວ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ກາງອອກແລ້ວ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index dc182c7dea53..88f9399c3a56 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -142,7 +142,7 @@
<string name="share_to_app_stop_dialog_title_generic" msgid="9079161538135843648">"Nebebendrinti?"</string>
<string name="share_to_app_stop_dialog_message_entire_screen_with_host_app" msgid="522823522115375414">"Šiuo metu bendrinate visą ekraną su šia programa: <xliff:g id="HOST_APP_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_entire_screen" msgid="5090115386271179270">"Šiuo metu bendrinate visą ekraną su programa"</string>
- <string name="share_to_app_stop_dialog_message_single_app_specific" msgid="5923772039347985172">"Šiuo metu bendrinate šią programą: <xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>"</string>
+ <string name="share_to_app_stop_dialog_message_single_app_specific" msgid="5923772039347985172">"Šiuo metu bendrinate programą „<xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>“"</string>
<string name="share_to_app_stop_dialog_message_single_app_generic" msgid="6681016774654578261">"Šiuo metu bendrinate programą"</string>
<string name="share_to_app_stop_dialog_message_generic" msgid="7622174291691249392">"Šiuo metu bendrinate su programa"</string>
<string name="share_to_app_stop_dialog_button" msgid="6334056916284230217">"Nebebendrinti"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Rodoma pokalbių pranešimų viršuje ir kaip profilio nuotrauka užrakinimo ekrane, burbule, pertraukia netrukdymo režimą"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetiniai"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko pokalbių funkcijų"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Atsiliepimai"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Uždaryti"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Neberodyti"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string>
@@ -1323,7 +1322,7 @@
<string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Norėdami perjungti tinklus, atjunkite eternetą"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Kad pagerintų įrenginio funkcijas, programos ir paslaugos vis tiek gali bet kada nuskaityti ieškodamos „Wi‑Fi“ tinklų, net jei „Wi‑Fi“ išjungtas. Tai galite pakeisti „Wi-Fi“ nuskaitymo nustatymuose. "<annotation id="link">"Pakeisti"</annotation></string>
- <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Išjungti lėktuvo režimą"</string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Išj. lėk. rež."</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ nori prie sparčiųjų nustatymų pridėti toliau pateiktą išklotinės elementą"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pridėti išklotinės elementą"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepridėti išklotinės elemento"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Lankstomasis įrenginys išlankstomas"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Lankstomasis įrenginys apverčiamas"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Priekinis ekranas įjungtas"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Slinkite, kad naudotumėte vidinį ekraną"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sulenkta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"nesulenkta"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
@@ -1486,7 +1486,7 @@
<string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naršykite naudodamiesi klaviatūra"</string>
<string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Sužinokite apie sparčiuosius klavišus"</string>
<string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naršykite naudodamiesi jutikline dalimi"</string>
- <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Sužinokite jutiklinės dalies gestus"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Peržvelkite jutiklinės dalies gestus"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naršykite naudodamiesi klaviatūra ir jutikline dalimi"</string>
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Sužinokite jutiklinės dalies gestus, sparčiuosius klavišus ir kt."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Grįžti"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5d7d87a0ac70..e0e38a140bee 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumulatora uzlādes līmenis procentos nav zināms."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ir izveidots savienojum ar <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Savienots ar ierīci <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Izvērst grupu."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Atvērt lietojumprogrammu."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Savienojums nav izveidots."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Viesabonēšana"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Izslēgti"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Izpētiet centra režīmu"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Piekļūstiet iecienītajiem logrīkiem un ekrānsaudzētājiem uzlādes laikā."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Aiziet!"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Uzlādes laikā rādīt izlases ekrānsaudzētājus"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"novelkamā izvēlne"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Parādās sarunu paziņojumu augšdaļā un kā profila attēls bloķēšanas ekrānā, arī kā burbulis, pārtrauc režīmu “Netraucēt”."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstītas sarunu funkcijas."</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Atsauksmes"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Nerādīt"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Vairs nerādīt"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šos paziņojumus nevar modificēt."</string>
@@ -966,7 +962,7 @@
<string name="right_keycode" msgid="2480715509844798438">"Taustiņu kods labajā pusē"</string>
<string name="left_icon" msgid="5036278531966897006">"Ikona kreisajā pusē"</string>
<string name="right_icon" msgid="1103955040645237425">"Ikona labajā pusē"</string>
- <string name="drag_to_add_tiles" msgid="8933270127508303672">"Lai pievienotu elementus, pieturiet tos un velciet"</string>
+ <string name="drag_to_add_tiles" msgid="8933270127508303672">"Lai pievienotu elementus, turiet un velciet tos"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Lai pārkārtotu elementus, turiet un velciet tos"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Lai noņemtu vienumus, velciet tos šeit."</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Nepieciešami vismaz <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> elementi"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Atvēršanai izmantojiet pirksta nospiedumu"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Nepieciešama autentifikācija. Pieskarieties pirksta nospieduma sensoram, lai veiktu autentificēšanu."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Notiekošs zvans"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Aktīva darbība"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilie dati"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ir izveidots savienojums"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Īslaicīgi izveidots savienojums"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Salokāma ierīce tiek atlocīta"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Salokāma ierīce tiek apgriezta"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Priekšējais ekrāns ir ieslēgts"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"aizvērta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"atvērta"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 22b5ff4823bf..0a9ca89fd4d3 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентот на батеријата е непознат."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Поврзано со <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Поврзано со <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Проширете ја групата."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Отворете ја апликацијата."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Не е поврзана"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Роаминг"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Исклучено"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Истражете го режимот Hub"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Пристапувајте до омилените виџети и штедачи на екран при полнење."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Ајде"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Прикажувајте ги омилените штедачи на екран при полнење"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"паѓачко мени"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијава ќе се избришат."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Се прикажува најгоре во известувањата за разговор и како профилна слика на заклучен екран, се појавува како балонче, го прекинува „Не вознемирувај“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритетно"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддржува функции за разговор"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Повратни информации"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Отфрли"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Не прикажувај повторно"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Овие известувања не може да се изменат"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Користете отпечаток за да се отвори"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Потребна е проверка. Допрете го сензорот за отпечаток за да автентицирате."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Тековен повик"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Во тек"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилен интернет"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Поврзано"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Привремено поврзано"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Преклопувачки уред се отклопува"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Преклопувачки уред се врти"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Предниот екран е вклучен"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворен"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворен"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 753b325df6b0..8ef9b7904765 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും ബബിൾ രൂപത്തിൽ ദൃശ്യമാകുന്നു, ശല്യപ്പെടുത്തരുത് മോഡ് തടസ്സപ്പെടുത്തുന്നു"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string>
<string name="no_shortcut" msgid="8257177117568230126">"സംഭാഷണ ഫീച്ചറുകളെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്‌ക്കുന്നില്ല"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ഫീഡ്ബാക്ക്"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"വീണ്ടും കാണിക്കരുത്"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം അൺഫോൾഡ് ആകുന്നു"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ഫോൾഡ് ചെയ്യാവുന്ന ഉപകരണം, കറങ്ങുന്ന വിധത്തിൽ ഫ്ലിപ്പ് ആകുന്നു"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ഫ്രണ്ട് സ്ക്രീൻ ഓണാക്കി"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"ഉള്ളിലുള്ള സ്‌ക്രീൻ ഉപയോഗിക്കുന്നതിന് സ്ലൈഡുചെയ്യുക"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ഫോൾഡ് ചെയ്തത്"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"അൺഫോൾഡ് ചെയ്തത്"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 9ef7ebd66cb3..feca24111f3d 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарейн хувь тодорхойгүй байна."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>-тай холбогдсон."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>-д холбогдсон."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Бүлгийг дэлгэнэ үү."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Аппликейшныг нээнэ үү."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Холбогдоогүй."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Идэвхгүй"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Hub горимыг судлах"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Цэнэглэж байхад дуртай виджет, дэлгэц амраагчдаа хандана уу."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"За эхэлцгээе"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Цэнэглэж байхдаа дуртай дэлгэц амраагчаа харуулна уу"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"эвхмэл цэс"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Харилцан ярианы мэдэгдлийн дээд талд болон түгжигдсэн дэлгэц дээр профайл зураг байдлаар харуулах бөгөөд бөмбөлөг хэлбэрээр харагдана. Бүү саад бол горимыг тасалдуулна"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Чухал"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь харилцан ярианы онцлогуудыг дэмждэггүй"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Санал хүсэлт"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Хаах"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Дахиж бүү харуул"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эдгээр мэдэгдлийг өөрчлөх боломжгүй."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Нээхийн тулд хурууны хээг ашиглана уу"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Баталгаажуулалт шаардлагатай. Баталгаажуулахын тулд хурууны хээ мэдрэгчид хүрнэ үү."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Үргэлжилж буй дуудлага"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Үргэлжилж байгаа"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобайл дата"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Холбогдсон"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Түр зуур холбогдсон"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Эвхэгддэг төхөөрөмжийг дэлгэж байна"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Эвхэгддэг төхөөрөмжийг хөнтөрч байна"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Нүүрэн талын дэлгэцийг асаасан"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"эвхсэн"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"дэлгэсэн"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 1327a48a1533..a3c45f3f0870 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"बॅटरीच्या चार्जिंगची टक्केवारी माहित नाही."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> शी कनेक्‍ट केले."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> शी कनेक्ट केले."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"गटाचा विस्तार करा."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"अ‍ॅप उघडा."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"कनेक्ट केले नाही."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"रोमिंग"</string>
<string name="cell_data_off" msgid="4886198950247099526">"बंद"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"हब मोड एक्सप्लोर करा"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"चार्ज करत असताना तुमचे आवडते विजेट आणि स्क्रीन सेव्हर अ‍ॅक्सेस करा."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"चला सुरू करू या"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"चार्ज करत असताना तुमचे आवडते स्क्रीनसेव्हर दाखवा"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"वापरकर्ता स्विच करा"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनू"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"संभाषण सूचनांच्या वरती आणि लॉक स्क्रीनवरील प्रोफाइल फोटो म्हणून दिसते, बबल म्हणून दिसते, व्यत्यय आणू नका यामध्ये अडथळा आणते"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राधान्य"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे संभाषण वैशिष्ट्यांना सपोर्ट करत नाही"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"फीडबॅक"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"डिसमिस करा"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"पुन्हा दाखवू नका"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"उघडण्यासाठी फिंगरप्रिंट वापरा"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ऑथेंटिकेशन आवश्यक आहे. ऑथेंटिकेट करण्यासाठी फिंगरप्रिंट सेन्सरला स्पर्श करा."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"सुरू असलेला कॉल"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"सुरू असलेले"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट केले आहे"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"तात्पुरते कनेक्ट केलेले"</string>
@@ -1399,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्ड करता येण्यासारखे डिव्हाइस अनफोल्ड केले जात आहे"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्ड करता येण्यासारखे डिव्हाइस आजूबाजूला फ्लिप केले जात आहे"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"पुढील स्क्रीन सुरू केलेली आहे"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"आतील स्क्रीन वापरण्यासाठी स्लाइड करा"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड केलेले"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"फोल्ड न केलेले"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 91901145c731..bb7dcb86428f 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -570,7 +570,7 @@
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Apabila anda berkongsi seluruh skrin anda, apa-apa sahaja kandungan pada skrin anda boleh dilihat oleh <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Apabila anda berkongsi apl, apa-apa sahaja kandungan yang dipaparkan atau dimainkan pada apl boleh dilihat oleh <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Apabila anda berkongsi apl, apa-apa sahaja kandungan yang dipaparkan atau dimainkan dalam apl tersebut boleh dilihat oleh <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Kongsi skrin"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah melumpuhkan pilihan ini"</string>
<string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Pilih apl untuk dikongsi"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ditunjukkan di bahagian atas pemberitahuan perbualan dan sebagai gambar profil pada skrin kunci, muncul sebagai gelembung, mengganggu Jangan Ganggu"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Keutamaan"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong ciri perbualan"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Maklum balas"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Ketepikan"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Jangan tunjukkan lagi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Pemberitahuan ini tidak boleh diubah suai."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Peranti boleh lipat dibuka"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Peranti boleh lipat diterbalikkan"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Skrin hadapan dihidupkan"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Luncurkan bar untuk menggunakan skrin dalaman"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"terlipat"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tidak terlipat"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 43f545dc4fbe..0219f695c6f0 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ဘက်ထရီရာခိုင်နှုန်းကို မသိပါ။"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>သို့ ချိတ်ဆက်ထား"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> သို့ချိတ်ဆက်ထားပါသည်။"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"အုပ်စုကို ပိုပြသည်။"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"အပလီကေးရှင်းကို ဖွင့်သည်။"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"ချိတ်ဆက်မထားပါ"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"ပြင်ပကွန်ရက်သုံးခြင်း"</string>
<string name="cell_data_off" msgid="4886198950247099526">"ပိတ်"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ထိန်းချုပ်စင်တာမုဒ် လေ့လာခြင်း"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"အားသွင်းနေစဉ် အကြိုက်ဆုံးဝိဂျက်များ၊ စခရင်နားချိန်ပုံများ ကြည့်နိုင်သည်။"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"စကြစို့"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"အားသွင်းနေစဉ် သင့်အကြိုက်ဆုံး စခရင်နားချိန်ပုံများကို ပြသည်"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ဆွဲချမီနူး"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"စကားဝိုင်း အကြောင်းကြားချက်များ၏ ထိပ်ပိုင်းနှင့် ပရိုဖိုင်ပုံအဖြစ် လော့ခ်မျက်နှာပြင်တွင် ပြသည်။ ပူဖောင်းကွက်အဖြစ် မြင်ရပြီး ‘မနှောင့်ယှက်ရ’ ကို ကြားဖြတ်သည်"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ဦးစားပေး"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းဝန်ဆောင်မှုများကို မပံ့ပိုးပါ"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"အကြံပြုချက်"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"ပယ်ရန်"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ထပ်မပြပါနှင့်"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ဖွင့်ရန် လက်ဗွေကို သုံးပါ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"အထောက်အထားစိစစ်ခြင်း လိုအပ်သည်။ အထောက်အထားစိစစ်ရန် လက်ဗွေ အာရုံခံကိရိယာကို ထိပါ။"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"လက်ရှိခေါ်ဆိုမှု"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"လုပ်ဆောင်နေဆဲ"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"မိုဘိုင်းဒေတာ"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ချိတ်ဆက်ထားသည်"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"ယာယီချိတ်ဆက်ထားသည်"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ခေါက်နိုင်သောစက်ကို ဖြန့်လိုက်သည်"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ခေါက်နိုင်သောစက်ကို တစ်ဘက်သို့ လှန်လိုက်သည်"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ရှေ့စခရင် ဖွင့်ထားသည်"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ခေါက်ထားသည်"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ဖြန့်ထားသည်"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index cc0574cc78ff..15e568b1c687 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -133,7 +133,7 @@
<string name="screenrecord_save_error" msgid="5862648532560118815">"Feil ved lagring av skjermopptaket"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Feil ved start av skjermopptaket"</string>
<string name="screenrecord_stop_dialog_title" msgid="8716193661764511095">"Vil du stoppe opptaket?"</string>
- <string name="screenrecord_stop_dialog_message" msgid="6262768207331626817">"Du tar nå opp hele skjermen"</string>
+ <string name="screenrecord_stop_dialog_message" msgid="6262768207331626817">"Nå tar du opptak av hele skjermen"</string>
<string name="screenrecord_stop_dialog_message_specific_app" msgid="5995770227684523244">"Du tar nå opp <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="screenrecord_stop_dialog_button" msgid="2883812564938194350">"Stopp opptaket"</string>
<string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Deler skjermen"</string>
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriprosenten er ukjent."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Koblet til <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Koblet til <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Utvid gruppen."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Åpne appen."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Ikke tilkoblet."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Av"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Utforsk Hub-modus"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Bruk moduler og skjermsparere mens du lader."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Sett i gang"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Vis skjermsparere du liker, under lading"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullegardinmeny"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apper og data i denne økten blir slettet."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Vises øverst på samtalevarsler og som et profilbilde på låseskjermen, vises som en boble, avbryter «Ikke forstyrr»"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalefunksjoner"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Tilbakemelding"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Lukk"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ikke vis igjen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse varslene kan ikke endres."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Bruk fingeravtrykk for å åpne"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering kreves. Trykk på fingeravtrykkssensoren for å autentisere."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Aktiv samtale"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Kontinuerlig"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Tilkoblet"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Koblet til midlertidig"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En foldbar enhet blir brettet ut"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En foldbar enhet blir snudd"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Frontskjermen er slått på"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"lagt sammen"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"åpen"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index cb0db8db416e..02285f209b88 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -169,7 +169,7 @@
<string name="immersive_cling_description" msgid="2717426731830851921">"यहाँबाट बाहिरिन स्क्रिनको सिरानबाट तलतिर स्वाइप गर्नुहोस्"</string>
<string name="immersive_cling_positive" msgid="3076681691468978568">"बुझेँ"</string>
<string name="accessibility_back" msgid="6530104400086152611">"पछाडि"</string>
- <string name="accessibility_home" msgid="5430449841237966217">"गृह"</string>
+ <string name="accessibility_home" msgid="5430449841237966217">"होम"</string>
<string name="accessibility_menu" msgid="2701163794470513040">"मेनु"</string>
<string name="accessibility_accessibility_button" msgid="4089042473497107709">"पहुँच"</string>
<string name="accessibility_rotate_button" msgid="1238584767612362586">"स्क्रिन घुमाउनुहोस्"</string>
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ब्याट्रीमा कति प्रतिशत चार्ज छ भन्ने कुराको जानाकरी छैन।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> मा जडित।"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> मा कनेक्ट गरियो।"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"समूह एक्स्पान्ड गर्नुहोस्।"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"एप खोल्नुहोस्।"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"जडान नगरिएको।"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"रोमिङ"</string>
<string name="cell_data_off" msgid="4886198950247099526">"निष्क्रिय पार्नु"</string>
@@ -352,7 +350,7 @@
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"बेनाम उपकरण"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कुनै उपकरणहरू उपलब्ध छैन"</string>
<string name="quick_settings_cast_no_network" msgid="3863016850468559522">"Wi-Fi वा इन्टरनेट कनेक्सन छैन"</string>
- <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"उज्यालपन"</string>
+ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ब्राइटनेस"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्भर्सन"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"कलर करेक्सन"</string>
<string name="quick_settings_font_scaling_label" msgid="5289001009876936768">"फन्टको आकार"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"हब मोडको अन्वेषण गर्नुहोस्"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"चार्ज गर्दै गर्दा आफूलाई मन पर्ने विजेट तथा स्क्रिन सेभर एक्सेस गर्नुहोस्।"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"सुरु गरौँ"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"चार्ज भइरहेका बेला आफूलाई मन पर्ने स्क्रिनसेभरहरू देखाउनुहोस्"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनु"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string>
@@ -565,7 +562,7 @@
<string name="media_projection_sys_service_dialog_title" msgid="3751133258891897878">"रेकर्ड वा कास्ट गर्न थाल्ने हो?"</string>
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"यो फङ्सन प्रदान गर्ने सेवाले रेकर्ड वा कास्ट गर्दै गर्दा तपाईंको स्क्रिनमा देखिने सबै जानकारी अथवा तपाईंको डिभाइसबाट प्ले गरिने सबै सामग्री हेर्न तथा प्रयोग गर्न सक्छ। यसअन्तर्गत पासवर्ड, भुक्तानीसम्बन्धी विवरण, फोटो, म्यासेज र तपाईंले प्ले गर्ने अडियो जस्ता कुराहरू समावेश हुन्छन्।"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"कुनै एप सेयर वा रेकर्ड गर्नुहोस्"</string>
- <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"स्क्रिन <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> सँग सेयर गर्ने हो?"</string>
+ <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"आफ्नो स्क्रिन <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> मा सेयर गर्ने हो?"</string>
<string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"एउटा एप सेयर गर्नुहोस्"</string>
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
<skip />
@@ -695,7 +692,7 @@
<string name="stream_ring" msgid="7550670036738697526">"घन्टी"</string>
<string name="stream_music" msgid="2188224742361847580">"मिडिया"</string>
<string name="stream_alarm" msgid="16058075093011694">"अलार्म"</string>
- <string name="stream_notification" msgid="7930294049046243939">"सूचना"</string>
+ <string name="stream_notification" msgid="7930294049046243939">"नोटिफिकेसन"</string>
<string name="stream_bluetooth_sco" msgid="6234562365528664331">"ब्लुटुथ"</string>
<string name="stream_dtmf" msgid="7322536356554673067">"दोहोरो बहु टोनको फ्रिक्वेन्सी"</string>
<string name="stream_accessibility" msgid="3873610336741987152">"पहुँच"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"यो वार्तालापका सूचनाहरूको सिरानमा, बबलका रूपमा र लक स्क्रिनमा प्रोफाइल फोटोका रूपमा देखिन्छ। साथै, यसले गर्दा \'बाधा नपुऱ्याउनुहोस्\' नामक सुविधामा अवरोध आउँछ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापसम्बन्धी सुविधा प्रयोग गर्न मिल्दैन"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"प्रतिक्रिया"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"हटाउनुहोस्"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"फेरि नदेखाउनुहोस्"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string>
@@ -862,7 +858,7 @@
<string name="keyboard_key_numpad_template" msgid="7316338238459991821">"नमप्याड <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="notif_inline_reply_remove_attachment_description" msgid="7954075334095405429">"एट्याचमेन्ट हटाउनुहोस्"</string>
<string name="keyboard_shortcut_group_system" msgid="1583416273777875970">"प्रणाली"</string>
- <string name="keyboard_shortcut_group_system_home" msgid="7465138628692109907">"गृह"</string>
+ <string name="keyboard_shortcut_group_system_home" msgid="7465138628692109907">"होम"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="8628108256824616927">"हालैका"</string>
<string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"पछाडि"</string>
<string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"नोटिफिकेसनहरू"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"फिंगरप्रिन्ट प्रयोग गरी खोल्नुहोस्"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि गर्नु पर्ने हुन्छ। पुष्टि गर्न फिंगरप्रिन्ट सेन्सर छुनुहोस्।"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"कल भइरहेको"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"जारी"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"इन्टरनेटमा कनेक्ट गरिएको छ"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"यसमा केही समयका लागि कनेक्ट गरिएको हो"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्डेबल डिभाइस अनफोल्ड गरेको देखाइएको एनिमेसन"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्डेबल डिभाइस यताउता पल्टाएर देखाइएको एनिमेसन"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"अगाडिको स्क्रिन अन गरिएको छ"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड गरिएको"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"अनफोल्ड गरिएको"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 326be99b8a65..85182a02faaf 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -110,12 +110,12 @@
<!-- Dark theme base colors for notification shade/scrim, the alpha component is adjusted
programmatically to match the spec -->
- <color name="shade_panel">@android:color/system_accent1_800</color>
- <color name="surface_effect_0">@android:color/system_accent1_800</color>
+ <color name="shade_panel_base">@android:color/system_accent1_800</color>
+ <color name="notification_scrim_base">@android:color/system_accent1_800</color>
- <!-- todo(b/388891904) Remove updated color references once they are available. -->
- <color name="shade_panel_base">@color/shade_panel</color>
- <color name="notification_scrim_base">@color/surface_effect_0</color>
+ <!-- Dark theme fallback colors for notification shade/scrim -->
+ <color name="shade_panel_fallback">@android:color/system_accent2_800</color>
+ <color name="notification_scrim_fallback">@android:color/system_surface_dim_dark</color>
<!-- Keyboard shortcut helper dialog -->
<color name="ksh_key_item_color">@*android:color/system_on_surface_variant_dark</color>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 26b88a951632..99c8838db1cc 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wordt getoond bovenaan gespreksmeldingen en als profielfoto op het vergrendelscherm, verschijnt als bubbel, onderbreekt Niet storen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksfuncties"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Sluiten"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Niet meer tonen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Deze meldingen kunnen niet worden aangepast."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Opvouwbaar apparaat wordt uitgevouwen"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Opvouwbaar apparaat wordt gedraaid"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Scherm aan voorzijde aangezet"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Schuiven om het binnenste scherm te gebruiken"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dichtgevouwen"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opengevouwen"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 768ab7acc026..5847a9a968ba 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଅଜଣା ଅଟେ।"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ସହ ସଂଯୁକ୍ତ"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> ସହିତ ସଂଯୁକ୍ତ।"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"ଗ୍ରୁପକୁ ବିସ୍ତାର କରନ୍ତୁ।"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"ଆପ୍ଲିକେସନ ଖୋଲନ୍ତୁ।"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"କନେକ୍ଟ ହୋଇନାହିଁ।"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"ରୋମିଙ୍ଗ"</string>
<string name="cell_data_off" msgid="4886198950247099526">"ବନ୍ଦ ଅଛି"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ହବ ମୋଡକୁ ଏକ୍ସପ୍ଲୋର କରନ୍ତୁ"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ଚାର୍ଜ କରିବା ସମୟରେ ଆପଣଙ୍କ ପସନ୍ଦର ୱିଜେଟ ଏବଂ ସ୍କ୍ରିନ ସେଭରଗୁଡ଼ିକୁ ଆକ୍ସେସ କରନ୍ତୁ।"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"ଚାଲନ୍ତୁ ଆରମ୍ଭ କରିବା"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"ଚାର୍ଜ କରିବା ସମୟରେ ଆପଣଙ୍କ ପସନ୍ଦର ସ୍କ୍ରିନସେଭରଗୁଡ଼ିକ ଦେଖାନ୍ତୁ"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍‍ ବଦଳାନ୍ତୁ"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ପୁଲଡାଉନ ମେନୁ"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍‌ ଓ ଡାଟା ଡିଲିଟ୍‌ ହୋଇଯିବ।"</string>
@@ -565,7 +562,7 @@
<string name="media_projection_sys_service_dialog_title" msgid="3751133258891897878">"ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ଆରମ୍ଭ କରିବେ?"</string>
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ରେକର୍ଡ ବା କାଷ୍ଟ କରିବା ସମୟରେ ଆପଣଙ୍କ ଡିଭାଇସରୁ ପ୍ଲେ ହେଉଥିବା କିମ୍ବା ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଦେଖାଯାଉଥିବା ସମସ୍ତ ସୂଚନାକୁ ଏହି ଫଙ୍କସନ ପ୍ରଦାନ କରୁଥିବା ସେବାର ଆକ୍ସେସ ରହିବ। ଏଥିରେ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ଫଟୋ, ମେସେଜ ଏବଂ ଆପଣ ପ୍ଲେ କରୁଥିବା ଅଡିଓ ପରି ସୂଚନା ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି।"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ଏକ ଆପକୁ ସେୟାର କିମ୍ବା ରେକର୍ଡ କରନ୍ତୁ"</string>
- <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ସହ ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ ସେୟାର କରନ୍ତୁ?"</string>
+ <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ସହ ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ ସେୟାର କରିବେ?"</string>
<string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ଗୋଟିଏ ଆପ ସେୟାର କରନ୍ତୁ"</string>
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
<skip />
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ, ଏକ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ, \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\'କୁ ବାଧା ଦିଏ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ପ୍ରାଥମିକତା"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ଫିଚରଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ମତାମତ"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"ଖାରଜ କରନ୍ତୁ"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ପୁଣି ଶୋ କରନ୍ତୁ ନାହିଁ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ଖୋଲିବାକୁ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ପ୍ରମାଣୀକରଣ ଆବଶ୍ୟକ। ପ୍ରମାଣୀକରଣ କରିବାକୁ ଟିପଚିହ୍ନ ସେନ୍ସରକୁ ସ୍ପର୍ଶ କରନ୍ତୁ।"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"ଚାଲିଥିବା କଲ"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"ଚାଲୁଥିବା"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ମୋବାଇଲ ଡାଟା"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ସଂଯୋଗ କରାଯାଇଛି"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"ଅସ୍ଥାୟୀ ରୂପେ କନେକ୍ଟ କରାଯାଇଛି"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଅନଫୋଲ୍ଡ କରାଯାଉଛି"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଫ୍ଲିପ କରାଯାଉଛି"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ସାମ୍ନା ସ୍କ୍ରିନ ଚାଲୁ ଅଛି"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ଫୋଲ୍ଡେଡ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ଅନଫୋଲ୍ଡେଡ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index a61ea1a37a7f..17757b896f5b 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਵਜੋਂ ਦਿਖਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਜੋ ਕਿ ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ ਅਤੇ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਸੁਵਿਧਾ ਵਿੱਚ ਵਿਘਨ ਵੀ ਪਾ ਸਕਦੀਆਂ ਹਨ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਗੱਲਬਾਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ਵਿਚਾਰ"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"ਖਾਰਜ ਕਰੋ"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਖੋਲ੍ਹਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ਮੋੜਨਯੋਗ ਡੀਵਾਈਸ ਨੂੰ ਆਲੇ-ਦੁਆਲੇ ਫਲਿੱਪ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ਅਗਲੀ ਸਕ੍ਰੀਨ ਚਾਲੂ ਕੀਤੀ ਗਈ"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"ਅੰਦਰਲੀ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਸਲਾਈਡ ਕਰੋ"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ਅਣਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 2e2a3b4623c0..c0a283113568 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Poziom naładowania baterii jest nieznany."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Połączono z <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Połączono z urządzeniem <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Rozwiń grupę."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Otwórz aplikację."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Nie połączono."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Wył."</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Odkryj tryb centrali"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Podczas ładowania możesz korzystać z ulubionych widżetów i wygaszaczy ekranu."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Do dzieła"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Podczas ładowania wyświetlaj ulubione wygaszacze ekranu"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
@@ -576,7 +573,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kiedy udostępniasz obraz z aplikacji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, widoczne jest wszystko to, co jest w niej wyświetlane lub odtwarzane. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Udostępnij ekran"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ma wyłączoną tę opcję"</string>
- <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Wybieranie aplikacji do udostępniania"</string>
+ <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Wybierz aplikację do udostępniania"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Włączyć przesyłanie treści wyświetlanych na ekranie?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Przesyłanie obrazu z 1 aplikacji"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Przesyłanie całego ekranu"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, jako dymek, przerywa działanie trybu Nie przeszkadzać"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorytetowe"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Opinia"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Zamknij"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Nie pokazuj ponownie"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"By otworzyć, użyj odcisku palca"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Wymagane uwierzytelnienie. Dotknij czytnika liniii papilarnych, by uwierzytelnić."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Trwa rozmowa"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"W toku"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilna transmisja danych"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Połączono"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tymczasowe połączenie"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Składane urządzenie jest rozkładane"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Składane urządzenie jest obracane"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ekran przedni jest włączony"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"po zamknięciu"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"po otwarciu"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index abba6885838b..c1a8ec4f5b0e 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -123,7 +123,7 @@
<string name="screenrecord_mic_label" msgid="2111264835791332350">"Microfone"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Áudio e microfone do dispositivo"</string>
<string name="screenrecord_continue" msgid="4055347133700593164">"Iniciar"</string>
- <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Gravando tela"</string>
+ <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Gravando a tela"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Gravando tela e áudio"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"Mostrar toques na tela"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"Parar"</string>
@@ -731,7 +731,7 @@
<string name="volume_panel_hint_muted" msgid="1124844870181285320">"som desativado"</string>
<string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"Áudio definido para"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde vai tocar:"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
<string name="status_bar" msgid="4357390266055077437">"Barra de status"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparecem na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão. Interrompem o Não perturbe."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string>
<string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Enviar feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Dispensar"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Não mostrar novamente"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
@@ -1140,7 +1139,7 @@
<string name="accessibility_floating_button_action_remove_menu" msgid="6730432848162552135">"Remover"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
<string name="accessibility_floating_button_action_edit" msgid="1688227814600463987">"Editar"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Controles do disp."</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Tela frontal ativada"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Deslize para usar a tela interna"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 833714c95e41..36384bce6ba2 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece na parte superior das notificações de conversas e como uma imagem do perfil no ecrã de bloqueio, surge como um balão, interrompe o modo Não incomodar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
<string name="no_shortcut" msgid="8257177117568230126">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta funcionalidades de conversa."</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Ignorar"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Não mostrar novamente"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável a ser desdobrado"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável a ser virado ao contrário"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ecrã frontal ativado"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Deslize lentamente para usar o ecrã interior"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index abba6885838b..c1a8ec4f5b0e 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -123,7 +123,7 @@
<string name="screenrecord_mic_label" msgid="2111264835791332350">"Microfone"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Áudio e microfone do dispositivo"</string>
<string name="screenrecord_continue" msgid="4055347133700593164">"Iniciar"</string>
- <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Gravando tela"</string>
+ <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Gravando a tela"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Gravando tela e áudio"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"Mostrar toques na tela"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"Parar"</string>
@@ -731,7 +731,7 @@
<string name="volume_panel_hint_muted" msgid="1124844870181285320">"som desativado"</string>
<string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"Áudio definido para"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde vai tocar:"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
<string name="status_bar" msgid="4357390266055077437">"Barra de status"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparecem na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão. Interrompem o Não perturbe."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string>
<string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Enviar feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Dispensar"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Não mostrar novamente"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
@@ -1140,7 +1139,7 @@
<string name="accessibility_floating_button_action_remove_menu" msgid="6730432848162552135">"Remover"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
<string name="accessibility_floating_button_action_edit" msgid="1688227814600463987">"Editar"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Controles do disp."</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Tela frontal ativada"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Deslize para usar a tela interna"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3cfe7b83fff9..beb3c1166684 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procentajul bateriei este necunoscut."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectat la <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"S-a stabilit conexiunea la <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Extinde grupul."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Deschide aplicația."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Neconectat."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Dezactivate"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Explorează modul hub"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Accesează widgeturile și screensaverele preferate în timpul încărcării."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Să începem"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Afișează screensaverele preferate în timpul încărcării"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Schimbă utilizatorul"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"meniu vertical"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Se afișează în partea de sus a notificărilor pentru conversații și ca fotografie de profil pe ecranul de blocare, apare ca un balon, întrerupe funcția Nu deranja"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritate"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă funcții pentru conversații"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Închide"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Nu mai afișa"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aceste notificări nu pot fi modificate."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Folosește amprenta ca să deschizi"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentificare obligatorie. Atinge senzorul de amprentă pentru a te autentifica."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Apel în desfășurare"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"În desfășurare"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Date mobile"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectat"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectat temporar"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispozitiv pliabil care este desfăcut"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispozitiv pliabil care este întors"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ecranul frontal este activat"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"închis"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"deschis"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7ec0513df942..e3f852c5bcc3 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Появляется в верхней части уведомлений о сообщениях, в виде всплывающего чата, а также в качестве фото профиля на заблокированном экране, прерывает режим \"Не беспокоить\"."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Оставить отзыв"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Закрыть"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Больше не показывать"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Складное устройство в разложенном виде"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Перевернутое складное устройство"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Передний экран включен"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Проведите пальцем, чтобы переключиться на внутренний экран."</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"устройство сложено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"устройство разложено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
@@ -1418,7 +1418,7 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Обнаружен пользователь"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string>
<string name="install_app" msgid="5066668100199613936">"Установить приложение"</string>
- <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"Чтобы продолжить, проведите вверх."</string>
+ <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"Чтобы продолжить, проведите вверх"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублировать на внешний дисплей?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Для внутреннего экрана включится дублирование. Передний экран будет отключен."</string>
<string name="mirror_display" msgid="2515262008898122928">"Дублировать"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 0a173cf0068f..9ff67479aed2 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"සංවාද දැනුම්දීම්වල ඉහළින්ම සහ අගුලු තිරයේ ඇති පැතිකඩ පින්තූරයක් ලෙස පෙන්වයි, බුබුළක් ලෙස දිස් වේ, බාධා නොකරන්න සඳහා බාධා කරයි"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ප්‍රමුඛතාව"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාද විශේෂාංගවලට සහාය නොදක්වයි"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ප්‍රතිපෝෂණය"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"අස් කරන්න"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"නැවත නොපෙන්වන්න"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"මෙම දැනුම්දීම් වෙනස් කළ නොහැක."</string>
@@ -1395,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"දිග හැරෙමින් පවතින නැමිය හැකි උපාංගය"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"වටා පෙරළෙමින් තිබෙන නැමිය හැකි උපාංගය"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ඉදිරිපස තිරය ක්‍රියාත්මකයි"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"නැවූ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"නොනැවූ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index fbbc48c877f8..a42eb1e6c35e 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje sa ako bublina v hornej časti upozornení konverzácie a profilová fotka na uzamknutej obrazovke, preruší režim bez vyrušení"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritné"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje funkcie konverzácie"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Spätná väzba"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Zavrieť"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Nabudúce nezobrazovať"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozloženie skladacieho zariadenia"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Prevrátenie skladacieho zariadenia"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Predná obrazovka je zapnutá"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Ak chcete použiť vnútornú obrazovku, prejdite prstom"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zložené"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 4174934bfedd..c0e751b82c9f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikaz v obliki oblačka na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu, preglasitev načina Ne moti."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prednostno"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira pogovornih funkcij."</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Povratne informacije"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Opusti"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Tega ne prikaži več"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Za ta obvestila ni mogoče spremeniti nastavitev."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Razpiranje zložljive naprave"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Obračanje zložljive naprave"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Sprednji zaslon je vklopljen"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Povlecite za uporabo notranjega zaslona"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zaprto"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"razprto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index f2c6301e1a0c..06cefd9c7734 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Përqindja e baterisë e panjohur."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Lidhur me <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Është lidhur me <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Zgjero grupin."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Hap aplikacionin."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Nuk është i lidhur."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Joaktiv"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Eksploro në modalitetin Hub"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Qasu në mbrojtësit e ekranit dhe miniaplikacionet e tua të preferuara gjatë karikimit."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Fillojmë"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Shfaq mbrojtësit e preferuar të ekranit gjatë karikimit"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyja me tërheqje poshtë"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shfaqet në krye të njoftimeve të bisedës dhe si fotografia e profilit në ekranin e kyçjes, shfaqet si flluskë dhe ndërpret modalitetin \"Mos shqetëso\""</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Me përparësi"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet veçoritë e bisedës"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Koment"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Hiq"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Mos e shfaq më"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Përdor gjurmën e gishtit për ta hapur"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kërkohet vërtetimi. Prek sensorin e gjurmës së gishtit për t\'u vërtetuar."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Telefonatë në vazhdim"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Në vazhdim"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Të dhënat celulare"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Lidhur"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Lidhur përkohësisht"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Pajisja e palosshme duke u hapur"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Pajisja e palosshme duke u rrotulluar"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ekrani i përparmë është aktivizuar"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"palosur"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"shpalosur"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 223242eb3cf9..3977058725a2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -109,14 +109,14 @@
<string name="screenrecord_title" msgid="4257171601439507792">"Снимач екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обрађујемо видео снимка екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Обавештење о сесији снимања екрана је активно"</string>
- <string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Желите да снимите екран?"</string>
- <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Сними једну апликацију"</string>
+ <string name="screenrecord_permission_dialog_title" msgid="7415261783188749730">"Желите да снимате екран?"</string>
+ <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"Снимaj једну апликацију"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="4882406311415082016">"Сними овај екран"</string>
<string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="4169494703993148253">"Сними %s"</string>
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Када снимате цео екран, снима се све што је на њему. Зато пазите на лозинке, информације о плаћању, поруке, слике, аудио и видео садржај."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Када снимате апликацију, снима се сав садржај који се приказује или пушта у њој. Зато пазите на лозинке, информације о плаћању, поруке, слике, аудио и видео садржај."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Сними екран"</string>
- <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Одаберите апликацију коју желите да снимите"</string>
+ <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Одаберите апликацију за снимање"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Снимај звук"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Звук уређаја"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Звук са уређаја, на пример, музика, позиви и мелодије звона"</string>
@@ -573,7 +573,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Када делите апликацију, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> види сав садржај који се приказује или пушта у њој. Зато пазите на лозинке, информације о плаћању, поруке, слике, аудио и видео садржај."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Дели екран"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је онемогућила ову опцију"</string>
- <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Одаберите апликацију коју желите да делите"</string>
+ <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Одаберите апликацију за дељење"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Желите да пребаците екран?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Пребаци једну апликацију"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Пребаци цео екран"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану, појављује се као облачић, прекида режим Не узнемиравај"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритетно"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава функције конверзације"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Повратне информације"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Одбаци"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Не приказуј поново"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Уређај на преклоп се отвара"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Уређај на преклоп се обрће"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Предњи екран је укључен"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Превуците да бисте користили унутрашњи екран"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index b61353517e5c..7051a2a92aa7 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Okänd batterinivå."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ansluten till <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Ansluten till <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Utöka gruppen."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Öppna appen."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Inte ansluten."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Av"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Utforska hubbläget"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Få åtkomst till dina favoritwidgetar och skärmsläckare under laddning."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Då kör vi"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Visa dina favoritskärmsläckare vid laddning"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullgardinsmeny"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Visas högst upp i konversationsaviseringarna och som profilbild på låsskärmen, visas som bubbla, åsidosätter Stör ej"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsfunktioner"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Stäng"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Visa inte igen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Öppna med fingeravtryck"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering krävs. Identifiera dig genom att trycka på fingeravtryckssensorn."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Pågående samtal"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Pågående"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ansluten"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tillfälligt ansluten"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En vikbar enhet viks upp"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En vikbar enhet vänds"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Den främre skärmen har aktiverats"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"hopvikt"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"uppvikt"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index cae856503bed..2ead01a37907 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Asilimia ya betri haijulikani."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Imeunganishwa kwenye <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Imeunganishwa kwenye <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Panua kikundi."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Fungua programu."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Haijaunganishwa."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Mitandao ya ng\'ambo"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Zima"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Gundua hali ya kutumia ikiwa imepachikwa"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Fikia wijeti unazopenda na taswira za skrini wakati unachaji."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Anza"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Onyesha taswira za skrini uzipendazo wakati wa kuchaji"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyu ya kuvuta chini"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Huonyeshwa kwenye sehemu ya juu ya arifa za mazungumzo na kama picha ya wasifu kwenye skrini iliyofungwa. Huonekana kama kiputo na hukatiza kipengele cha Usinisumbue"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii vipengele vya mazungumzo"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Maoni"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Ondoa"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Usionyeshe tena"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Tumia alama ya kidole kufungua"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Uthibitishaji unahitajika. Gusa kitambua alama ya kidole ili uthibitishe."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Simu inayoendelea"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Inaendelea"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Data ya mtandao wa simu"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Imeunganishwa"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Imeunganishwa kwa muda"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Kifaa kinachokunjwa kikikunjuliwa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Kifaa kinachokunjwa kikigeuzwa"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Umewasha skrini ya mbele"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kimekunjwa"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kimefunguliwa"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index d9781b6accc9..b37350cc3b82 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -116,14 +116,14 @@
<string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"முழுத் திரையை நீங்கள் ரெக்கார்டு செய்யும்போது அதில் காட்டப்படும் அனைத்தும் ரெக்கார்டு செய்யப்படும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
<string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"ஓர் ஆப்ஸை ரெக்கார்டு செய்யும்போது அதில் காட்டப்படும் அல்லது பிளே செய்யப்படும் அனைத்தும் ரெக்கார்டு செய்யப்படும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
<string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"திரையை ரெக்கார்டு செய்"</string>
- <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"ரெக்கார்டு செய்ய ஆப்ஸைத் தேர்வுசெய்தல்"</string>
+ <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"ரெக்கார்டு செய்ய ஆப்ஸைத் தேர்வுசெய்க"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"ஆடியோவை ரெக்கார்டு செய்தல்"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"சாதன ஆடியோ"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"இசை, அழைப்புகள், ரிங்டோன்கள் போன்ற உங்கள் சாதனத்திலிருந்து வரும் ஒலி"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"மைக்ரோஃபோன்"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"சாதன ஆடியோ மற்றும் மைக்ரோஃபோன்"</string>
<string name="screenrecord_continue" msgid="4055347133700593164">"தொடங்கு"</string>
- <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"ஸ்கிரீன் ரெக்கார்ட் செய்யப்படுகிறது"</string>
+ <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"ஸ்கிரீன் ரெக்கார்டு செய்யப்படுகிறது"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"ஸ்கிரீன் மற்றும் ஆடியோ ரெக்கார்ட் செய்யப்படுகிறது"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"திரையில் உள்ள தொடுதல்களைக் காட்டு"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"நிறுத்து"</string>
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"பேட்டரி சதவீதம் தெரியவில்லை."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>க்கு இணைக்கப்பட்டது."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> உடன் இணைக்கப்பட்டுள்ளது."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"குழுவை விரிவாக்கும்."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"ஆப்ஸைத் திறக்கும்."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"இணைக்கப்படவில்லை."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"ரோமிங்"</string>
<string name="cell_data_off" msgid="4886198950247099526">"ஆஃப்"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ஹப் பயன்முறையைக் கண்டறியுங்கள்"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"சார்ஜிங்கின்போது உங்களுக்குப் பிடித்த விட்ஜெட்களையும் ஸ்கிரீன் சேவர்களையும் அணுகலாம்."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"தொடங்குக"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"சார்ஜாகும்போது உங்களுக்கு விருப்பமான ஸ்கிரீன் சேவர்களைக் காட்டும்"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"பயனரை மாற்று"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"கீழ் இழுக்கும் மெனு"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string>
@@ -576,7 +573,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ஓர் ஆப்ஸைப் பகிரும்போது, அதில் காட்டப்படும்/பிளே செய்யப்படும் அனைத்தும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> இல் தெரியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"திரையைப் பகிர்"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் இந்த விருப்பத்தை முடக்கியுள்ளது"</string>
- <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"பகிர ஆப்ஸைத் தேர்வுசெய்தல்"</string>
+ <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"பகிர ஆப்ஸைத் தேர்வுசெய்க"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"உங்கள் திரையை அலைபரப்ப வேண்டுமா?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"ஓர் ஆப்ஸை அலைபரப்பு"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"முழுத்திரையையும் அலைபரப்பு"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"உரையாடல் அறிவிப்புகளின் மேற்பகுதியில் காட்டப்படும், திரை பூட்டப்பட்டிருக்கும்போது சுயவிவரப் படமாகக் காட்டப்படும், குமிழாகத் தோன்றும், தொந்தரவு செய்ய வேண்டாம் அம்சம் இயக்கப்பட்டிருக்கும்போதும் காட்டப்படும்"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string>
<string name="no_shortcut" msgid="8257177117568230126">"உரையாடல் அம்சங்களை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"கருத்து"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"மூடுக"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"மீண்டும் காட்டாதே"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"கைரேகையைப் பயன்படுத்தி திறந்திடுங்கள்"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"அங்கீகாரம் தேவை. கைரேகை சென்சாரைத் தொட்டு அங்கீகரியுங்கள்."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"செயலில் உள்ள அழைப்பு"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"செயலிலுள்ளது"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"மொபைல் டேட்டா"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"இணைக்கப்பட்டது"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"தற்காலிகமாக இணைக்கப்பட்டுள்ளது"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"மடக்கத்தக்க சாதனம் திறக்கப்படுகிறது"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"மடக்கத்தக்க சாதனம் ஃபிளிப் செய்யப்பட்டு திருப்பப்படுகிறது"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"முன்பக்கத் திரை இயக்கப்பட்டுள்ளது"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"மடக்கப்பட்டது"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"விரிக்கப்பட்டது"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index e31f8662b38e..f64c737d8236 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -123,7 +123,7 @@
<string name="screenrecord_mic_label" msgid="2111264835791332350">"మైక్రోఫోన్"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"పరికరం ఆడియో, మైక్రోఫోన్"</string>
<string name="screenrecord_continue" msgid="4055347133700593164">"ప్రారంభించండి"</string>
- <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"స్క్రీన్ రికార్డింగ్ చేయబడుతోంది"</string>
+ <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"స్క్రీన్, ఆడియో రికార్డింగ్ చేయబడుతున్నాయి"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"స్క్రీన్‌పై తాకే స్థానాలను చూపండి"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"ఆపివేయండి"</string>
@@ -562,7 +562,7 @@
<string name="media_projection_sys_service_dialog_title" msgid="3751133258891897878">"రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string>
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు మీ స్క్రీన్‌పై చూపబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, ఈ ఫంక్షన్‌ను అందిస్తున్న సర్వీస్ యాక్సెస్ చేయగలదు. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్‌లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"యాప్‌ను షేర్ చేయండి లేదా రికార్డ్ చేయండి"</string>
- <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"మీ స్క్రీన్‌ను <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‌తో షేర్ చేయండి?"</string>
+ <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"మీ స్క్రీన్‌ను <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‌కు షేర్ చేయాలా?"</string>
<string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ఒక యాప్‌ను షేర్ చేయండి"</string>
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
<skip />
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"సంభాషణ నోటిఫికేషన్‌ల ఎగువున, లాక్ స్క్రీన్‌లో ప్రొఫైల్ ఫోటో‌గా చూపిస్తుంది, బబుల్‌గా కనిపిస్తుంది, \'అంతరాయం కలిగించవద్దు\'ను అంతరాయం కలిగిస్తుంది"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> సంభాషణ ఫీచర్‌లను సపోర్ట్ చేయదు"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ఫీడ్‌బ్యాక్"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"విస్మరించండి"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"మళ్లీ చూపవద్దు"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్‌లను ఎడిట్ చేయడం వీలుపడదు."</string>
@@ -1395,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"మడవగల పరికరం విప్పబడుతోంది"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"మడవగల పరికరం చుట్టూ తిప్పబడుతోంది"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ముందు వైపు స్క్రీన్ ఆన్ అయింది"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"మడిచే సదుపాయం గల పరికరం"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"మడిచే సదుపాయం లేని పరికరం"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 8f34f8a2122e..316aab0270ff 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"แสดงที่ด้านบนของการแจ้งเตือนการสนทนาและเป็นรูปโปรไฟล์บนหน้าจอล็อก ปรากฏเป็นบับเบิล แสดงในโหมดห้ามรบกวน"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"สำคัญ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับฟีเจอร์การสนทนา"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ความคิดเห็น"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"ปิด"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ไม่ต้องแสดงอีก"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"แก้ไขการแจ้งเตือนเหล่านี้ไม่ได้"</string>
@@ -1395,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"อุปกรณ์ที่พับได้กำลังกางออก"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"อุปกรณ์ที่พับได้กำลังพลิกไปมา"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"เปิดหน้าจอด้านหน้าแล้ว"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"เลื่อนเพื่อใช้หน้าจอด้านใน"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"พับ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"กางออก"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 2c72bd80c031..04dc6c7c7680 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -138,7 +138,7 @@
<string name="screenrecord_stop_dialog_button" msgid="2883812564938194350">"Huminto sa pag-record"</string>
<string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"Ibinabahagi ang screen"</string>
<string name="share_to_app_chip_accessibility_label_generic" msgid="5517431657924536133">"Pagbabahagi ng content"</string>
- <string name="share_to_app_stop_dialog_title" msgid="9212915050910250438">"Ihinto ang pagbabahagi ng screen?"</string>
+ <string name="share_to_app_stop_dialog_title" msgid="9212915050910250438">"Ihinto ang pagshe-share ng screen?"</string>
<string name="share_to_app_stop_dialog_title_generic" msgid="9079161538135843648">"Itigil ang pagbabahagi?"</string>
<string name="share_to_app_stop_dialog_message_entire_screen_with_host_app" msgid="522823522115375414">"Kasalukuyan mong ibinabahagi ang iyong buong screen sa <xliff:g id="HOST_APP_NAME">%1$s</xliff:g>"</string>
<string name="share_to_app_stop_dialog_message_entire_screen" msgid="5090115386271179270">"Kasalukuyan mong ibinabahagi ang iyong buong screen sa isang app"</string>
@@ -562,7 +562,7 @@
<string name="media_projection_sys_service_dialog_title" msgid="3751133258891897878">"Magsimulang mag-record o mag-cast?"</string>
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Ang serbisyong nagbibigay ng function na ito ay magkakaroon ng access sa lahat ng impormasyong nakikita sa iyong screen o pine-play mula sa device mo habang nagre-record o nagka-cast. Kasama rito ang impormasyong tulad ng mga password, detalye ng pagbabayad, larawan, mensahe, at audio na pine-play mo."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Magbahagi o mag-record ng app"</string>
- <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Ibahagi ang iyong screen sa <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+ <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"I-share ang screen mo sa <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
<string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Mag-share ng isang app"</string>
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
<skip />
@@ -570,10 +570,10 @@
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kapag ibinahagi mo ang iyong buong screen, makikita ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang kahit anong nasa screen mo. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kapag nagbabahagi ka ng app, makikita ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kapag nagshe-share ka ng app, makikita ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ibahagi ang screen"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Na-disable ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang opsyong ito"</string>
- <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Pumili ng app na ibabahagi"</string>
+ <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Pumili ng app na ishe-share"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"I-cast ang iyong screen?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Mag-cast ng isang app"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"I-cast ang buong screen"</string>
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Makikita sa itaas ng mga notification ng pag-uusap at bilang larawan sa profile sa lock screen, lumalabas bilang bubble, naaabala ang Huwag Istorbohin"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priyoridad"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang mga feature ng pag-uusap"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"I-dismiss"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Huwag nang ipakita ulit"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hindi puwedeng baguhin ang mga notification na ito."</string>
@@ -1395,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ina-unfold na foldable na device"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Fini-flip na foldable na device"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Na-on ang screen sa harap"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"naka-fold"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"hindi naka-fold"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4ca73158c240..f4a2c9260398 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -231,7 +231,7 @@
<string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"Parmak izi kilidi kurulamadı. Tekrar denemek için Ayarlar\'a gidin."</string>
<string name="face_re_enroll_notification_title" msgid="1850838867718410520">"Yüz Tanıma Kilidi\'ni tekrar kurun"</string>
<string name="face_re_enroll_notification_name" msgid="7384545252206120659">"Yüz Tanıma Kilidi"</string>
- <string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Yüz Tanıma Kilidi\'ni kurun"</string>
+ <string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Yüz Tanıma Kilidi\'ni ayarla"</string>
<string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"Yüz Tanıma Kilidi\'ni tekrar kurmak için mevcut yüz modeliniz silinir.\n\nYüzünüzü kullanarak telefonunuzun kilidini açmak için bu özelliği yeniden kurmanız gerekir."</string>
<string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Yüz tanıma kilidi kurulamadı. Tekrar denemek için Ayarlar\'a gidin."</string>
<string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Parmak izi sensörüne dokunun"</string>
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pil yüzdesi bilinmiyor."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ile bağlı."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> bağlantısı kuruldu."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Grubu genişlet."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Uygulama aç."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Bağlanmadı."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Dolaşım"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Kapalı"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Hub Modu\'nu keşfedin"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Cihazınız şarj olurken en sevdiğiniz widget\'lara ve ekran koruyuculara erişin."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Başlayalım"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Cihazınız şarj olurken en sevdiğiniz ekran koruyucuları gösterin"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"açılır menü"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Görüşme bildirimlerinin üstünde ve kilit ekranında profil resmi olarak gösterilir, baloncuk olarak görünür, Rahatsız Etmeyin\'i kesintiye uğratır"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Öncelikli"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>, sohbet özelliklerini desteklemiyor"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Geri bildirim"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Kapat"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Tekrar gösterme"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmak için parmak izi kullanın"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kimlik doğrulaması gerekiyor. Kimlik doğrulaması için parmak izi sensörüne dokunun."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Devam eden arama"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Devam ediyor"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil veri"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Bağlı"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Geçici olarak bağlandı"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Katlanabilir cihaz açılıyor"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Katlanabilir cihaz döndürülüyor"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ön ekran açıldı"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"katlanmış"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"katlanmamış"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index bf4444ee8898..7dab3db1d310 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Відсоток заряду акумулятора невідомий."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Підключено до <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Під’єднано до пристрою <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Розгорнути групу"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Відкрити додаток"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Не з’єднано."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Роумінг"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Вимкнено"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Представляємо режим центру керування"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Використовуйте улюблені віджети й заставки, поки пристрій заряджається."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Почати"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Показувати улюблені заставки під час заряджання"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"спадне меню"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string>
@@ -565,7 +562,7 @@
<string name="media_projection_sys_service_dialog_title" msgid="3751133258891897878">"Почати запис або трансляцію?"</string>
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Сервіс, що надає цю функцію, матиме доступ до всієї інформації, яка з’являється на екрані або відтворюється на пристрої під час запису чи трансляції, зокрема до паролів, платіжної інформації, фотографій, повідомлень і аудіофайлів."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Показувати або записувати додаток"</string>
- <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Показати екран для додатка <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+ <string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Показати екран у додатку <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
<string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Показати один додаток"</string>
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
<skip />
@@ -573,10 +570,10 @@
<!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
<skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Коли ви показуєте весь екран, для додатка <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> стає видимим увесь контент на ньому. Тому будьте обережні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
- <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Коли ви показуєте додаток, для додатка <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> стає видимим увесь контент, що відображається або відтворюється в ньому. Тому будьте обережні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
+ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Коли ви показуєте вікно додатка, увесь контент, що відображається або відтворюється в ньому, стає видимим у додатку <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Тому будьте обережні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Показати екран"</string>
<string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> вимкнув цю опцію"</string>
- <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Виберіть додаток, яким хочете поділитися"</string>
+ <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Виберіть додаток для показу"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Транслювати екран?"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Транслювати один додаток"</string>
<string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Транслювати весь екран"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З’являється вгорі сповіщень про розмови і як зображення профілю на заблокованому екрані, відображається як спливаючий чат, перериває режим \"Не турбувати\""</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує функції розмов"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Надіслати відгук"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Закрити"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Більше не показувати"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Щоб відкрити, використайте відбиток пальця"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Пройдіть автентифікацію. Для цього торкніться сканера відбитків пальців."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Поточний дзвінок"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Поточна активність"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобільний трафік"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Підключено"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Тимчасово з’єднано"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Розкладний пристрій у розкладеному стані"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Розкладний пристрій обертається"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Передній екран увімкнено"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складений"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"розкладений"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 584375f8ac5f..646072122204 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -123,7 +123,7 @@
<string name="screenrecord_mic_label" msgid="2111264835791332350">"مائیکروفون"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"آلہ کا آڈیو اور مائیکروفون"</string>
<string name="screenrecord_continue" msgid="4055347133700593164">"شروع کریں"</string>
- <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"ریکارڈنگ اسکرین"</string>
+ <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"اسکرین ریکارڈ ہو رہی ہے"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"اسکرین اور آڈیو کی ریکارڈنگ ہو رہی ہے"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"اسکرین پر کئے گئے ٹچز دکھائیں"</string>
<string name="screenrecord_stop_label" msgid="72699670052087989">"روکیں"</string>
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"بیٹری کی فیصد نامعلوم ہے۔"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> سے منسلک ہیں۔"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> سے منسلک ہے۔"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"گروپ کو پھیلائیں۔"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"ایپلیکیشن کھولیں۔"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"مربوط نہیں ہے۔"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"رومنگ"</string>
<string name="cell_data_off" msgid="4886198950247099526">"آف ہے"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ہب موڈ دریافت کریں"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"چارج کرتے وقت اپنے پسندیدہ ویجیٹس اور اسکرین سیورز تک رسائی حاصل کریں۔"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"آئیے شروع کریں"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"چارج کرتے وقت اپنے پسندیدہ اسکرین سیورز دکھائیں"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"صارف سوئچ کریں"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"پل ڈاؤن مینیو"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"یہ گفتگو کی اطلاعات کے اوپری حصّے پر اور مقفل اسکرین پر پروفائل کی تصویر کے بطور دکھائی دیتا ہے، بلبلے کے بطور ظاہر ہوتا ہے، \'ڈسٹرب نہ کریں\' میں مداخلت کرتا ہے"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ گفتگو کی خصوصیات کو سپورٹ نہیں کرتی ہے"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"تاثرات"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"برخاست کریں"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"دوبارہ نہ دکھائیں"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"کھولنے کے لیے فنگر پرنٹ کا استعمال کریں"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"توثیق مطلوب ہے۔ توثیق کرنے کے لیے فنگر پرنٹ سینسر کو ٹچ کریں۔"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"جاری کال"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"جاری ہے"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"موبائل ڈیٹا"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"منسلک ہے"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"عارضی طور پر منسلک ہے"</string>
@@ -1399,6 +1394,7 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"فولڈ ہونے والے آلے کو کھولا جا رہا ہے"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"فولڈ ہونے والے آلے کو گھمایا جا رہا ہے"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"فرنٹ اسکرین آن ہے"</string>
+ <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"اندرونی اسکرین کا استعمال کرنے کے لیے سلائیڈ کریں"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"فولڈ کردہ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"اَن فولڈ کردہ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index c69346f95c5c..6bcd9d6c4c1c 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -804,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Suhbat bildirishnomalari tepasida va ekran qulfida profil rasmi sifatida chiqariladi, bulutcha sifatida chiqadi, Bezovta qilinmasin rejimini bekor qiladi"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Muhim"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat funksiyalari ishlamaydi"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Fikr-mulohaza"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Yopish"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Boshqa chiqmasin"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string>
@@ -1395,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Buklanadigan qurilma ochilmoqda"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Buklanadigan qurilma aylantirilmoqda"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Old ekran yoqildi"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"buklangan"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"buklanmagan"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index eee95832f1ab..a9f24ed1da78 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Tỷ lệ phần trăm pin không xác định."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Đã kết nối với <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Đã kết nối với <xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Mở rộng nhóm."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Mở ứng dụng."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Chưa được kết nối."</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Chuyển vùng"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Tắt"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Khám phá chế độ thiết bị trung tâm"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Truy cập vào các tiện ích và trình bảo vệ màn hình mà bạn yêu thích trong khi sạc."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Bắt đầu"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Hiện trình bảo vệ màn hình bạn yêu thích trong khi sạc"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"trình đơn kéo xuống"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Hiện ở đầu phần thông báo cuộc trò chuyện và ở dạng ảnh hồ sơ trên màn hình khóa, xuất hiện ở dạng bong bóng, làm gián đoạn chế độ Không làm phiền"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Mức độ ưu tiên"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ các tính năng trò chuyện"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Phản hồi"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Đóng"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Không hiện lại"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Dùng vân tay để mở"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Bạn cần phải xác thực. Hãy chạm vào cảm biến vân tay để xác thực."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Cuộc gọi đang diễn ra"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Đang diễn ra"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dữ liệu di động"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Đã kết nối"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Tạm thời có kết nối"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Thiết bị có thể gập lại đang được mở ra"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Thiết bị có thể gập lại đang được lật ngược"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Đã bật màn hình trước"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gập"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"mở"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 81f1bffdf4ab..0f28d9299d68 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"电池电量百分比未知。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已连接到<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"已连接到 <xliff:g id="CAST">%s</xliff:g>。"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"展开群组。"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"打开应用。"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"未连接。"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"漫游"</string>
<string name="cell_data_off" msgid="4886198950247099526">"已关闭"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"探索基座接入模式"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"充电时访问您喜爱的微件和屏保。"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"现在就试试吧"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"在充电时显示您喜爱的屏保"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切换用户"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉菜单"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以气泡形式显示在对话通知顶部(屏幕锁定时显示为个人资料照片),并且会中断勿扰模式"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"优先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话功能"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"反馈"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"关闭"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"不再显示"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"无法修改这些通知。"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指纹即可打开"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要进行身份验证。请轻触指纹传感器以验证身份。"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"正在通话"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"正在进行"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"移动数据网络"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已连接"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"已暂时连接"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展开可折叠设备"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻转可折叠设备"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"前屏已开启"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折叠状态"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"展开状态"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index b21f13f8102c..6a29d86bb49f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"電量百分比不明。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"已連接至 <xliff:g id="CAST">%s</xliff:g>。"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"展開群組。"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"開啟應用程式。"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"未連線。"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"漫遊"</string>
<string name="cell_data_off" msgid="4886198950247099526">"關閉"</string>
@@ -377,7 +375,7 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"工作應用程式"</string>
<string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"已暫停"</string>
- <string name="quick_settings_night_display_label" msgid="8180030659141778180">"夜間模式"</string>
+ <string name="quick_settings_night_display_label" msgid="8180030659141778180">"夜燈模式"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"在日落時開啟"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"在日出時關閉"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> 開啟"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"探索插座模式"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"在充電時存取你喜愛的小工具和螢幕保護程式。"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"立即開始"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"充電時顯示常用螢幕保護程式"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以對話氣泡形式顯示在對話通知頂部 (在上鎖畫面會顯示為個人檔案相片),並會中斷「請勿打擾」模式"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"意見反映"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"關閉"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"不要再顯示"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。掂一下指紋感應器就可以驗證。"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"通話中"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"進行中"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"流動數據"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"已暫時連線"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開折疊式裝置"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"正面螢幕已開啟"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已打開"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index f2b0b86411e7..a931304cdfbe 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -250,10 +250,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"電池電量不明。"</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"已連線至 <xliff:g id="CAST">%s</xliff:g>。"</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"展開群組。"</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"開啟應用程式。"</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"尚未連線。"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"漫遊"</string>
<string name="cell_data_off" msgid="4886198950247099526">"關閉"</string>
@@ -543,8 +541,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"瞭解 Hub 模式"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"在充電時使用喜愛的小工具和螢幕保護程式。"</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"開始使用"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"在充電時顯示你最愛的螢幕保護程式"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會刪除。"</string>
@@ -807,8 +804,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以對話框的形式顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片),並會中斷「零打擾」模式"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"意見回饋"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"關閉"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"不要再顯示"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
@@ -1308,8 +1304,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。輕觸指紋感應器即可進行驗證。"</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"通話中"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"進行中"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"行動數據"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"已暫時建立連線"</string>
@@ -1399,6 +1394,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開的折疊式裝置"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"正面螢幕已開啟"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已展開"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 445bdc013dfb..08e685273bb3 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -252,10 +252,8 @@
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Iphesenti lebhethri alaziwa."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Xhuma ku-<xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"Ixhumeke ku-<xliff:g id="CAST">%s</xliff:g>."</string>
- <!-- no translation found for accessibility_expand_group (521237935987978624) -->
- <skip />
- <!-- no translation found for accessibility_open_application (1749126077501259712) -->
- <skip />
+ <string name="accessibility_expand_group" msgid="521237935987978624">"Nweba iqembu."</string>
+ <string name="accessibility_open_application" msgid="1749126077501259712">"Vula i-application."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Akuxhunyiwe"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Iyazulazula"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Valiwe"</string>
@@ -545,8 +543,7 @@
<string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Hlola imodi yehabhu"</string>
<string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Finyelela amawijethi akho ayintandokazi nezigcinisikrini ngenkathi ushaja."</string>
<string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Asihambe"</string>
- <!-- no translation found for glanceable_hub_to_dream_button_tooltip (9018287673822335829) -->
- <skip />
+ <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Bonisa izigcini zesikrini zakho eziyintandokazi ngenkathi ishaja"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Shintsha umsebenzisi"</string>
<string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"imenyu yokudonsela phansi"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wonke ama-app nedatha kulesi sikhathi azosuswa."</string>
@@ -809,8 +806,7 @@
<string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ivela phezu kwezaziso zengxoxo futhi njengesithombe sephrofayela esikrinini sokukhiya, ivela njengebhamuza, ukuphazamisa okuthi Ungaphazamisi"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Okubalulekile"</string>
<string name="no_shortcut" msgid="8257177117568230126">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli izici zengxoxo"</string>
- <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) -->
- <skip />
+ <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Impendulo"</string>
<string name="notification_inline_dismiss" msgid="88423586921134258">"Chitha"</string>
<string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ungabonisi futhi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Lezi zaziso azikwazi ukushintshwa."</string>
@@ -1310,8 +1306,7 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Sebenzisa izigxivizo zeminwe ukuvula"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Ukufakazela ubuqiniso budingekile. Thinta inzwa yezigxivizo zeminwe ukuze uqinisekise."</string>
<string name="ongoing_call_content_description" msgid="6394763878322348560">"Ikholi eqhubekayo"</string>
- <!-- no translation found for ongoing_notification_extra_content_description (2098752668861351265) -->
- <skip />
+ <string name="ongoing_notification_extra_content_description" msgid="2098752668861351265">"Okuqhubekayo"</string>
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Idatha yeselula"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ixhunyiwe"</string>
<string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Ixhume okwesikhashana"</string>
@@ -1401,6 +1396,8 @@
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Idivayisi egoqekayo iyembulwa"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Idivayisi egoqekayo iphendulwa nxazonke"</string>
<string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Isikrini sangaphambili sivuliwe"</string>
+ <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) -->
+ <skip />
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kugoqiwe"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kuvuliwe"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5f8f77993245..8665fd6dcaf5 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -34,12 +34,12 @@
<!-- Base colors for notification shade/scrim, the alpha component is adjusted programmatically
to match the spec -->
- <color name="shade_panel">@android:color/system_accent1_900</color>
- <color name="surface_effect_0">@android:color/system_accent1_100</color>
+ <color name="shade_panel_base">@android:color/system_accent1_900</color>
+ <color name="notification_scrim_base">@android:color/system_accent1_100</color>
- <!-- todo(b/388891904) Remove updated color references once they are available. -->
- <color name="shade_panel_base">@color/shade_panel</color>
- <color name="notification_scrim_base">@color/surface_effect_0</color>
+ <!-- Fallback colors for notification shade/scrim -->
+ <color name="shade_panel_fallback">@android:color/system_accent2_200</color>
+ <color name="notification_scrim_fallback">@android:color/system_surface_dim_light</color>
<!-- The color of the background in the separated list of the Global Actions menu -->
<color name="global_actions_separated_background">#F5F5F5</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 09aa2241e42b..8d10e393b5ca 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -119,7 +119,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,font_scaling,record_issue,hearing_devices,notes
+ internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,font_scaling,record_issue,hearing_devices,notes,desktopeffects
</string>
<!-- The tiles to display in QuickSettings -->
@@ -175,6 +175,9 @@
<!-- Minimum display time for a heads up notification if throttling is enabled, in milliseconds. -->
<integer name="heads_up_notification_minimum_time_with_throttling">500</integer>
+ <!-- Minimum display time for a heads up notification that was shown from a user action (like tapping on a different part of the UI), in milliseconds. -->
+ <integer name="heads_up_notification_minimum_time_for_user_initiated">3000</integer>
+
<!-- Display time for a sticky heads up notification, in milliseconds. -->
<integer name="sticky_heads_up_notification_time">60000</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 648e4c2e3ac7..7d0c393f53b5 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -203,16 +203,32 @@
<!-- Size of the view displaying the mobile signal icon in the status bar. This value should
match the core/status_bar_system_icon_size and change to sp unit -->
<dimen name="status_bar_mobile_signal_size">15sp</dimen>
- <dimen name="status_bar_mobile_signal_size_updated">14sp</dimen>
+ <dimen name="status_bar_mobile_signal_size_updated">12sp</dimen>
+
<!-- Size of the view displaying the mobile signal icon in the status bar. This value should
- match the viewport height of mobile signal drawables such as ic_lte_mobiledata -->
+ match the viewport height of mobile signal drawables such as ic_lte_mobiledata
+ Note: can be removed once new_status_bar_icons is rolled out -->
<dimen name="status_bar_mobile_type_size">16sp</dimen>
<!-- Size of the view that contains the network type. Should be equal to
- status_bar_mobile_type_size + 2, to account for 1sp top and bottom padding -->
+ status_bar_mobile_type_size + 2, to account for 1sp top and bottom padding
+ Note: can be removed once new_status_bar_icons is rolled out -->
<dimen name="status_bar_mobile_container_height">18sp</dimen>
<!-- Corner radius for the background of the network type indicator. Should be equal to
- status_bar_mobile_container_height / 2 -->
+ status_bar_mobile_container_height / 2
+ Note: can be removed once new_status_bar_icons is rolled out -->
<dimen name="status_bar_mobile_container_corner_radius">9sp</dimen>
+
+ <!-- Size of the view displaying the mobile signal icon in the status bar. This value should
+ match the viewport height of mobile signal drawables such as ic_lte_mobiledata -->
+ <dimen name="status_bar_mobile_type_size_updated">12sp</dimen>
+ <!-- Size of the view that contains the network type. Should be equal to
+ status_bar_mobile_type_size + 2, to account for 1sp top and bottom padding -->
+ <dimen name="status_bar_mobile_container_height_updated">14sp</dimen>
+ <dimen name="status_bar_mobile_container_margin_end">2sp</dimen>
+ <!-- Corner radius for the background of the network type indicator. Should be equal to
+ status_bar_mobile_container_height / 2 -->
+ <dimen name="status_bar_mobile_container_corner_radius_updated">7sp</dimen>
+
<!-- Size of the view displaying the mobile roam icon in the status bar. This value should
match the viewport size of drawable stat_sys_roaming -->
<dimen name="status_bar_mobile_roam_size">8sp</dimen>
@@ -1242,8 +1258,11 @@
<dimen name="min_window_blur_radius">1px</dimen>
<dimen name="max_window_blur_radius">23px</dimen>
+ <!-- Blur radius of the Notification Shade content (notifications, footer, shelf) -->
+ <dimen name="max_shade_content_blur_radius">@dimen/max_window_blur_radius</dimen>
+
<!-- Blur radius behind Notification Shade -->
- <dimen name="max_shade_window_blur_radius">60dp</dimen>
+ <dimen name="max_shade_window_blur_radius">34dp</dimen>
<!-- How much into a DisplayCutout's bounds we can go, on each side -->
<dimen name="display_cutout_margin_consumption">0px</dimen>
@@ -1254,6 +1273,8 @@
<dimen name="ongoing_appops_chip_side_padding">8dp</dimen>
<!-- Margin between icons of Ongoing App Ops chip -->
<dimen name="ongoing_appops_chip_icon_margin">4dp</dimen>
+ <!-- Side margins for the content of an appops chip -->
+ <dimen name="ongoing_appops_chip_content_horizontal_margin">10dp</dimen>
<!-- Icon size of Ongoing App Ops chip -->
<dimen name="ongoing_appops_chip_icon_size">16sp</dimen>
<!-- Radius of Ongoing App Ops chip corners -->
@@ -1305,7 +1326,8 @@
<dimen name="qs_media_seekbar_progress_amplitude">1.5dp</dimen>
<dimen name="qs_media_seekbar_progress_phase">8dp</dimen>
<dimen name="qs_media_seekbar_progress_stroke_width">2dp</dimen>
- <dimen name="qs_media_session_collapsed_guideline">144dp</dimen>
+ <dimen name="qs_media_session_collapsed_legacy_guideline">144dp</dimen>
+ <dimen name="qs_media_session_collapsed_guideline">168dp</dimen>
<!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
<dimen name="qs_media_rec_default_width">380dp</dimen>
@@ -1800,7 +1822,8 @@
<!-- The activity chip side padding, used with the default phone icon. -->
<dimen name="ongoing_activity_chip_side_padding">12dp</dimen>
<!-- The activity chip side padding, used with an icon that has embedded padding (e.g. if the icon comes from the notification's smallIcon field). If the icon has padding, the chip itself can have less padding. -->
- <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon">6dp</dimen>
+ <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon">2dp</dimen>
+ <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon_legacy">6dp</dimen>
<!-- The icon size, used with the default phone icon. -->
<dimen name="ongoing_activity_chip_icon_size">16dp</dimen>
<!-- The icon size, used with an icon that has embedded padding. (If the icon has embedded padding, we need to make the whole icon larger so the icon itself doesn't look small.) -->
@@ -2136,18 +2159,25 @@
<dimen name="volume_dialog_width">60dp</dimen>
<dimen name="volume_dialog_background_corner_radius">30dp</dimen>
- <dimen name="volume_dialog_background_vertical_margin">-10dp</dimen>
+ <dimen name="volume_dialog_background_vertical_margin">
+ @dimen/volume_dialog_buttons_margin_negative
+ </dimen>
<!-- top margin covers half the ringer button + components spacing -->
<dimen name="volume_dialog_background_top_margin">-28dp</dimen>
+ <dimen name="volume_dialog_window_margin">14dp</dimen>
<dimen name="volume_dialog_components_spacing">8dp</dimen>
<dimen name="volume_dialog_floating_sliders_spacing">8dp</dimen>
<dimen name="volume_dialog_floating_sliders_vertical_padding">10dp</dimen>
- <dimen name="volume_dialog_floating_sliders_vertical_padding_negative">-10dp</dimen>
+ <dimen name="volume_dialog_floating_sliders_vertical_padding_negative">
+ @dimen/volume_dialog_buttons_margin_negative
+ </dimen>
<dimen name="volume_dialog_floating_sliders_horizontal_padding">4dp</dimen>
<dimen name="volume_dialog_button_size">40dp</dimen>
<dimen name="volume_dialog_slider_width">52dp</dimen>
<dimen name="volume_dialog_slider_height">254dp</dimen>
+ <dimen name="volume_dialog_buttons_margin">10dp</dimen>
+ <dimen name="volume_dialog_buttons_margin_negative">-10dp</dimen>
<!--
A primary goal of this margin is to vertically constraint slider height in the landscape
orientation when the vertical space is limited
@@ -2160,7 +2190,11 @@
<dimen name="volume_dialog_background_square_corner_radius">12dp</dimen>
- <dimen name="volume_dialog_ringer_drawer_margin">10dp</dimen>
+ <dimen name="volume_dialog_ringer_drawer_margin">@dimen/volume_dialog_buttons_margin</dimen>
+ <!--
+ (volume_dialog_slider_width - volume_dialog_button_size) / 2
+ This centers ringer drawer against the volume slider
+ -->
<dimen name="volume_dialog_ringer_drawer_diff_end_margin">6dp</dimen>
<dimen name="volume_dialog_ringer_drawer_button_size">@dimen/volume_dialog_button_size</dimen>
<dimen name="volume_dialog_ringer_drawer_button_icon_radius">10dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 86292039d93d..c0eea15b043b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2098,7 +2098,13 @@
<string name="notification_inline_dismiss">Dismiss</string>
<!-- [CHAR LIMIT=30] Text shown in button used to prevent app from showing Live Updates, for this notification and all future ones -->
- <string name="notification_inline_disable_promotion">Don\'t show again</string>
+ <string name="notification_inline_disable_promotion">Don\'t show as pinned</string>
+
+ <!-- Text accompanying the "Show live updates" switch explaining the purpose of the setting -->
+ <string name="live_notifications_title">Showing Live Updates</string>
+
+ <!-- Text accompanying the "Show live updates" switch explaining the purpose of the setting -->
+ <string name="live_notifications_desc">Pinned notifications display live info from apps, and always appear on the status bar and lock screen</string>
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be modified.</string>
@@ -2335,7 +2341,9 @@
<!-- User visible title for the keyboard shortcut that enters split screen with current app on the left [CHAR LIMIT=70] -->
<string name="system_multitasking_lhs">Use split screen with app on the left</string>
<!-- User visible title for the keyboard shortcut that switches from split screen to full screen [CHAR LIMIT=70] -->
- <string name="system_multitasking_full_screen">Switch to full screen</string>
+ <string name="system_multitasking_full_screen">Use full screen</string>
+ <!-- User visible title for the keyboard shortcut that switches to desktop view [CHAR LIMIT=70] -->
+ <string name="system_multitasking_desktop_view">Use desktop view</string>
<!-- User visible title for the keyboard shortcut that switches to app on right or below while using split screen [CHAR LIMIT=70] -->
<string name="system_multitasking_splitscreen_focus_rhs">Switch to app on right or below while using split screen</string>
<!-- User visible title for the keyboard shortcut that switches to app on left or above while using split screen [CHAR LIMIT=70] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4961a7ece69a..8f808d389203 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -93,6 +93,19 @@
<item name="android:textColor">?android:attr/colorPrimary</item>
</style>
+ <style name="StatusBar.EventChip">
+ <item name="android:orientation">horizontal</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:gravity">center</item>
+ <item name="android:clipToOutline">true</item>
+ <item name="android:background">@drawable/statusbar_chip_bg</item>
+ <item name="android:minHeight">@dimen/ongoing_appops_chip_height</item>
+ <item name="android:maxWidth">@dimen/ongoing_appops_chip_max_width</item>
+ <item name="android:minWidth">@dimen/ongoing_appops_chip_min_width</item>
+ </style>
+
<style name="Chipbar" />
<style name="Chipbar.Text" parent="@*android:style/TextAppearance.DeviceDefault.Notification.Title">
diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml
index d885e00fbe82..faf06f3d39f0 100644
--- a/packages/SystemUI/res/values/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values/tiles_states_strings.xml
@@ -358,4 +358,14 @@
<item>Off</item>
<item>On</item>
</string-array>
+
+ <!-- State names for desktop effects tile: unavailable, off, on.
+ This subtitle is shown when the tile is in that particular state but does not set its own
+ subtitle, so some of these may never appear on screen. They should still be translated as
+ if they could appear. [CHAR LIMIT=32] -->
+ <string-array name="tile_states_desktopeffects">
+ <item>Unavailable</item>
+ <item>Off</item>
+ <item>On</item>
+ </string-array>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index 66c54a389c8e..b5efd04eeba9 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -64,6 +64,13 @@
app:layout_constraintBottom_toBottomOf="@+id/album_art" />
<Constraint
+ android:id="@+id/action_button_guideline"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintGuide_end="@dimen/qs_media_session_collapsed_legacy_guideline" />
+
+ <Constraint
android:id="@+id/header_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml
index a8f616c2427d..dcc5d4f6635f 100644
--- a/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml
+++ b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml
@@ -8,7 +8,7 @@
android:layout_width="@dimen/volume_dialog_slider_width"
android:layout_height="0dp"
android:layout_marginTop="@dimen/volume_dialog_slider_vertical_margin"
- android:layout_marginEnd="@dimen/volume_dialog_components_spacing"
+ android:layout_marginEnd="@dimen/volume_dialog_window_margin"
android:layout_marginBottom="@dimen/volume_dialog_slider_vertical_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml
index b4d8ae791f36..3a5e41d5781a 100644
--- a/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml
+++ b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml
@@ -8,7 +8,7 @@
android:layout_width="@dimen/volume_dialog_slider_width"
android:layout_height="0dp"
android:layout_marginTop="@dimen/volume_dialog_slider_vertical_margin"
- android:layout_marginEnd="@dimen/volume_dialog_components_spacing"
+ android:layout_marginEnd="@dimen/volume_dialog_window_margin"
android:layout_marginBottom="@dimen/volume_dialog_slider_vertical_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/packages/SystemUI/res/xml/volume_dialog_ringer_drawer_motion_scene.xml b/packages/SystemUI/res/xml/volume_dialog_ringer_drawer_motion_scene.xml
index 1607121f230f..4c3dbd78cc3e 100644
--- a/packages/SystemUI/res/xml/volume_dialog_ringer_drawer_motion_scene.xml
+++ b/packages/SystemUI/res/xml/volume_dialog_ringer_drawer_motion_scene.xml
@@ -20,30 +20,9 @@
android:id="@+id/close_to_open_transition"
app:constraintSetEnd="@+id/volume_dialog_ringer_drawer_open"
app:constraintSetStart="@+id/volume_dialog_ringer_drawer_close"
- app:transitionEasing="cubic(0.05, 0.7, 0.1, 1.0)"
- app:duration="400">
- </Transition>
-
- <ConstraintSet android:id="@+id/volume_dialog_ringer_drawer_close">
- <Constraint
- android:id="@+id/volume_ringer_drawer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
- </ConstraintSet>
-
- <ConstraintSet android:id="@+id/volume_dialog_ringer_drawer_open">
- <Constraint
- android:id="@+id/volume_ringer_drawer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"/>
- </ConstraintSet>
+ app:duration="400"
+ app:transitionEasing="cubic(0.05, 0.7, 0.1, 1.0)" />
+ <ConstraintSet android:id="@+id/volume_dialog_ringer_drawer_close" />
+ <ConstraintSet android:id="@+id/volume_dialog_ringer_drawer_open" />
</MotionScene> \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 82ac78c6db15..0372a6c6d2c5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -20,7 +20,6 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
-import static com.android.systemui.Flags.glanceableHubBackAction;
import static com.android.systemui.shared.Flags.shadeAllowBackGesture;
import android.annotation.LongDef;
@@ -361,10 +360,6 @@ public class QuickStepContract {
}
// Disable back gesture on the hub, but not when the shade is showing.
if ((sysuiStateFlags & SYSUI_STATE_COMMUNAL_HUB_SHOWING) != 0) {
- // Allow back gesture on Glanceable Hub with back action support.
- if (glanceableHubBackAction()) {
- return false;
- }
// Use QS expanded signal as the notification panel is always considered visible
// expanded when on the lock screen and when opening hub over lock screen. This does
// mean that back gesture is disabled when opening shade over hub while in portrait
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index ff6bcdb150f8..fcde508b07a8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -16,6 +16,7 @@
package com.android.systemui.shared.system;
+import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.RemoteAnimationTarget;
@@ -42,5 +43,5 @@ public interface RecentsAnimationListener {
* Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control.
*/
- void onTasksAppeared(RemoteAnimationTarget[] app);
+ void onTasksAppeared(RemoteAnimationTarget[] app, @Nullable TransitionInfo transitionInfo);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index f528ec8af134..860a496ef18b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -20,22 +20,16 @@ import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.hardware.biometrics.BiometricSourceType;
import android.os.SystemClock;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.util.ViewController;
-import java.lang.ref.WeakReference;
-
import javax.inject.Inject;
/**
@@ -54,39 +48,8 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
private Pair<BiometricSourceType, Long> mMessageBiometricSource = null;
private static final Long SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS = 3500L;
- /**
- * Delay before speaking an accessibility announcement. Used to prevent
- * lift-to-type from interrupting itself.
- */
- private static final long ANNOUNCEMENT_DELAY = 250;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
- private final AnnounceRunnable mAnnounceRunnable;
- private final TextWatcher mTextWatcher = new TextWatcher() {
- @Override
- public void afterTextChanged(Editable editable) {
- CharSequence msg = editable;
- if (!TextUtils.isEmpty(msg)) {
- mView.removeCallbacks(mAnnounceRunnable);
- mAnnounceRunnable.setTextToAnnounce(msg);
- mView.postDelayed(() -> {
- if (msg == mView.getText()) {
- mAnnounceRunnable.run();
- }
- }, ANNOUNCEMENT_DELAY);
- }
- }
-
- @Override
- public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
- /* no-op */
- }
-
- @Override
- public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
- /* no-op */
- }
- };
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
public void onFinishedGoingToSleep(int why) {
@@ -122,7 +85,6 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
- mAnnounceRunnable = new AnnounceRunnable(mView);
}
@Override
@@ -131,14 +93,12 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
mView.setSelected(mKeyguardUpdateMonitor.isDeviceInteractive());
mView.onThemeChanged();
- mView.addTextChangedListener(mTextWatcher);
}
@Override
protected void onViewDetached() {
mConfigurationController.removeCallback(mConfigurationListener);
mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
- mView.removeTextChangedListener(mTextWatcher);
}
/**
@@ -232,30 +192,4 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
view, mKeyguardUpdateMonitor, mConfigurationController);
}
}
-
- /**
- * Runnable used to delay accessibility announcements.
- */
- @VisibleForTesting
- public static class AnnounceRunnable implements Runnable {
- private final WeakReference<View> mHost;
- private CharSequence mTextToAnnounce;
-
- AnnounceRunnable(View host) {
- mHost = new WeakReference<>(host);
- }
-
- /** Sets the text to announce. */
- public void setTextToAnnounce(CharSequence textToAnnounce) {
- mTextToAnnounce = textToAnnounce;
- }
-
- @Override
- public void run() {
- final View host = mHost.get();
- if (host != null && host.isVisibleToUser()) {
- host.announceForAccessibility(mTextToAnnounce);
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 5d63c2a92ba8..4a4cb7a232c5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -43,6 +43,8 @@ import com.android.internal.widget.LockPatternView;
import com.android.settingslib.animation.AppearAnimationCreator;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
+import com.android.systemui.Flags;
+import com.android.systemui.bouncer.shared.constants.PatternBouncerConstants.ColorId;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
@@ -227,6 +229,18 @@ public class KeyguardPatternView extends KeyguardInputView
super.onFinishInflate();
mLockPatternView = findViewById(R.id.lockPatternView);
+ if (Flags.bouncerUiRevamp2()) {
+ mLockPatternView.setDotColors(mContext.getColor(ColorId.dotColor), mContext.getColor(
+ ColorId.activatedDotColor));
+ mLockPatternView.setColors(mContext.getColor(ColorId.pathColor), 0, 0);
+ mLockPatternView.setDotSizes(
+ getResources().getDimensionPixelSize(R.dimen.keyguard_pattern_dot_size),
+ getResources().getDimensionPixelSize(
+ R.dimen.keyguard_pattern_activated_dot_size));
+ mLockPatternView.setPathWidth(
+ getResources().getDimensionPixelSize(R.dimen.keyguard_pattern_stroke_width));
+ mLockPatternView.setKeepDotActivated(true);
+ }
mEcaView = findViewById(R.id.keyguard_selector_fade_container);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index fbe9edfd6680..04d4c2a3cdf9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -41,6 +41,7 @@ import androidx.annotation.CallSuper;
import com.android.app.animation.Interpolators;
import com.android.internal.widget.LockscreenCredential;
+import com.android.systemui.Flags;
import com.android.systemui.res.R;
import java.util.ArrayList;
@@ -178,7 +179,15 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
mOkButton = findViewById(R.id.key_enter);
+ if (Flags.bouncerUiRevamp2()) {
+ mOkButton.setImageResource(R.drawable.pin_bouncer_confirm);
+ }
mDeleteButton = findViewById(R.id.delete_button);
+ if (Flags.bouncerUiRevamp2()) {
+ mDeleteButton.setDrawableForTransparentMode(R.drawable.pin_bouncer_delete_filled);
+ mDeleteButton.setDefaultDrawable(R.drawable.pin_bouncer_delete_outline);
+ mDeleteButton.setImageResource(R.drawable.pin_bouncer_delete_outline);
+ }
mDeleteButton.setVisibility(View.VISIBLE);
mButtons[0] = findViewById(R.id.key0);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index 5a9cbce73e4b..892851cd7056 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -173,6 +173,11 @@ public interface KeyguardViewController {
boolean isBouncerShowing();
/**
+ * Report when the UI is ready for dismissing the whole Keyguard.
+ */
+ void readyForKeyguardDone();
+
+ /**
* Stop showing the alternate bouncer, if showing.
*
* <p>Should be like calling {@link #hideAlternateBouncer(boolean, boolean)} with a {@code true}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index 2f74158107f2..69e4fd7c3d53 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -15,6 +15,7 @@
*/
package com.android.keyguard;
+import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
@@ -33,6 +34,9 @@ import com.android.systemui.Flags;
import com.android.systemui.bouncer.shared.constants.PinBouncerConstants.Animation;
import com.android.systemui.bouncer.shared.constants.PinBouncerConstants.Color;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Provides background color and radius animations for key pad buttons.
*/
@@ -141,6 +145,7 @@ class NumPadAnimator {
mExpandAnimator.addUpdateListener(
anim -> mBackground.setCornerRadius((float) anim.getAnimatedValue()));
+ List<Animator> expandAnimators = new ArrayList<>();
ValueAnimator expandBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
mNormalBackgroundColor, mPressedBackgroundColor);
expandBackgroundColorAnimator.setDuration(Animation.expansionColorDuration);
@@ -162,10 +167,27 @@ class NumPadAnimator {
}
});
+ expandAnimators.add(mExpandAnimator);
+ expandAnimators.add(expandBackgroundColorAnimator);
+ expandAnimators.add(expandTextColorAnimator);
+
+ if (Flags.bouncerUiRevamp2()) {
+ ValueAnimator expandTextScaleAnimator = ValueAnimator.ofFloat(
+ Animation.normalTextScaleX, Animation.pressedTextScaleX);
+ expandTextScaleAnimator.setInterpolator(Animation.expansionInterpolator);
+ expandTextScaleAnimator.setDuration(Animation.expansionDuration);
+ expandTextScaleAnimator.addUpdateListener(valueAnimator -> {
+ if (mDigitTextView != null) {
+ mDigitTextView.setTextScaleX((Float) valueAnimator.getAnimatedValue());
+ }
+ });
+ expandAnimators.add(expandTextScaleAnimator);
+ }
+
mExpandAnimatorSet = new AnimatorSet();
- mExpandAnimatorSet.playTogether(mExpandAnimator,
- expandBackgroundColorAnimator, expandTextColorAnimator);
+ mExpandAnimatorSet.playTogether(expandAnimators);
+ List<Animator> contractAnimators = new ArrayList<>();
mContractAnimator = ValueAnimator.ofFloat(1f, 0f);
mContractAnimator.setStartDelay(Animation.contractionStartDelay);
mContractAnimator.setDuration(Animation.contractionDuration);
@@ -195,9 +217,24 @@ class NumPadAnimator {
}
});
+ contractAnimators.add(mContractAnimator);
+ contractAnimators.add(contractBackgroundColorAnimator);
+ contractAnimators.add(contractTextColorAnimator);
+
+ if (Flags.bouncerUiRevamp2()) {
+ ValueAnimator contractTextScaleAnimator = ValueAnimator.ofFloat(
+ Animation.pressedTextScaleX, Animation.normalTextScaleX);
+ contractTextScaleAnimator.setInterpolator(Animation.contractionRadiusInterpolator);
+ contractTextScaleAnimator.setDuration(Animation.contractionDuration);
+ contractTextScaleAnimator.addUpdateListener(valueAnimator -> {
+ if (mDigitTextView != null) {
+ mDigitTextView.setTextScaleX((Float) valueAnimator.getAnimatedValue());
+ }
+ });
+ contractAnimators.add(contractTextScaleAnimator);
+ }
mContractAnimatorSet = new AnimatorSet();
- mContractAnimatorSet.playTogether(mContractAnimator,
- contractBackgroundColorAnimator, contractTextColorAnimator);
+ mContractAnimatorSet.playTogether(contractAnimators);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 0ff93236a856..584ebb50520a 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -25,6 +25,7 @@ import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import com.android.systemui.Flags;
@@ -42,6 +43,12 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni
private int mStyleAttr;
private boolean mIsTransparentMode;
+ @DrawableRes
+ private int mDrawableForTransparentMode = 0;
+
+ @DrawableRes
+ private int mDefaultDrawable = 0;
+
public NumPadButton(Context context, AttributeSet attrs) {
super(context, attrs);
mStyleAttr = attrs.getStyleAttribute();
@@ -123,8 +130,14 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni
mIsTransparentMode = isTransparentMode;
if (isTransparentMode) {
+ if (mDrawableForTransparentMode != 0) {
+ setImageResource(mDrawableForTransparentMode);
+ }
setBackgroundColor(getResources().getColor(android.R.color.transparent));
} else {
+ if (mDefaultDrawable != 0) {
+ setImageResource(mDefaultDrawable);
+ }
Drawable bgDrawable = getContext().getDrawable(R.drawable.num_pad_key_background);
if (Flags.bouncerUiRevamp2() && bgDrawable != null) {
bgDrawable.setTint(Color.actionBg);
@@ -154,4 +167,19 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni
super.onInitializeAccessibilityNodeInfo(info);
info.setTextEntryKey(true);
}
+
+ /**
+ * Drawable to use when transparent mode is enabled
+ */
+ public void setDrawableForTransparentMode(@DrawableRes int drawableResId) {
+ mDrawableForTransparentMode = drawableResId;
+ }
+
+ /**
+ * Drawable to use when transparent mode is not enabled.
+ */
+ public void setDefaultDrawable(@DrawableRes int drawableResId) {
+ mDefaultDrawable = drawableResId;
+ setImageResource(mDefaultDrawable);
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index b152ff348e22..56aadc342424 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -148,7 +148,7 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener {
if (bouncerUiRevamp2()) {
mDigitText.setTypeface(
- Typeface.create(FontStyles.GSF_LABEL_LARGE_EMPHASIZED, Typeface.NORMAL));
+ Typeface.create(FontStyles.GSF_LABEL_SMALL_EMPHASIZED, Typeface.NORMAL));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
index ca83724aaf07..7af37bd720e3 100644
--- a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
@@ -129,6 +129,11 @@ class CameraAvailabilityListener(
listeners.remove(callback)
}
+ fun debugFaceAuth(id: Int) {
+ val info = cameraProtectionInfoList?.getOrNull(id)
+ if (info != null) notifyCameraActive(info)
+ }
+
private fun isExcluded(packageId: String): Boolean {
return excludedPackageIds.contains(packageId)
}
diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
index dbdf93d81eee..8bb236b91860 100644
--- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
@@ -87,7 +87,7 @@ class FaceScanningOverlay(
override fun enableShowProtection(isCameraActive: Boolean) {
val scanningAnimationRequiredWhenCameraActive =
- keyguardUpdateMonitor.isFaceDetectionRunning || authController.isShowing
+ keyguardUpdateMonitor.isFaceDetectionRunning || authController.isShowing || mDebug
val faceAuthSucceeded = keyguardUpdateMonitor.isFaceAuthenticated
val showScanningAnimationNow = scanningAnimationRequiredWhenCameraActive && isCameraActive
if (showScanningAnimationNow == showScanningAnim) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index da206facd1fb..e7253533aa42 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -189,7 +189,7 @@ public class ScreenDecorations implements
@VisibleForTesting
protected void showCameraProtection(@NonNull Path protectionPath, @NonNull Rect bounds) {
- if (mFaceScanningFactory.shouldShowFaceScanningAnim()) {
+ if (mDebug || mFaceScanningFactory.shouldShowFaceScanningAnim()) {
DisplayCutoutView overlay = (DisplayCutoutView) getOverlayView(
mFaceScanningViewId);
if (overlay != null) {
@@ -395,6 +395,12 @@ public class ScreenDecorations implements
setupDecorations();
});
}
+
+ if (cmd.getFaceAuthScreen() != null) {
+ mExecutor.execute(() -> {
+ debugTriggerFaceAuth(cmd.getFaceAuthScreen());
+ });
+ }
};
@Override
@@ -630,6 +636,15 @@ public class ScreenDecorations implements
}
}
+ private void debugTriggerFaceAuth(int screen) {
+ DisplayCutoutView overlay = (DisplayCutoutView) getOverlayView(
+ mFaceScanningViewId);
+ if (overlay != null) {
+ overlay.setDebug(true);
+ mCameraListener.debugFaceAuth(screen);
+ }
+ }
+
private void setupDecorations() {
Trace.beginSection("ScreenDecorations#setupDecorations");
setupDecorationsInner();
@@ -1360,6 +1375,7 @@ public class ScreenDecorations implements
final List<Rect> mBounds = new ArrayList();
final Rect mBoundingRect = new Rect();
Rect mTotalBounds = new Rect();
+ boolean mDebug = false;
private int mColor = Color.BLACK;
private int mRotation;
@@ -1378,6 +1394,10 @@ public class ScreenDecorations implements
}
}
+ public void setDebug(boolean debug) {
+ mDebug = debug;
+ }
+
public void setColor(int color) {
if (color == mColor) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index e2065f175c79..85f18800f20b 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -126,7 +126,7 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
}
};
- private final int mFalsingThreshold;
+ private int mFalsingThreshold;
private boolean mTouchAboveFalsingThreshold;
private boolean mDisableHwLayers;
private final boolean mFadeDependingOnAmountSwiped;
@@ -149,8 +149,7 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
// Extra long-press!
mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
- mDensityScale = resources.getDisplayMetrics().density;
- mFalsingThreshold = resources.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
+ updateResourceProperties(resources);
mFadeDependingOnAmountSwiped = resources.getBoolean(
R.bool.config_fadeDependingOnAmountSwiped);
mFalsingManager = falsingManager;
@@ -165,6 +164,14 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
getMaxEscapeAnimDuration() / 1000f);
}
+ /** Update ane properties that depend on Resources */
+ public void updateResourceProperties(Resources resources) {
+ float density = resources.getDisplayMetrics().density;
+ setDensityScale(density);
+ mCallback.onDensityScaleChange(density);
+ mFalsingThreshold = resources.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
+ }
+
public void setDensityScale(float densityScale) {
mDensityScale = densityScale;
}
@@ -1001,5 +1008,8 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
* @return If true, the given view is draggable.
*/
default boolean canChildBeDragged(@NonNull View animView) { return true; }
+
+ /** The density scale has changed */
+ void onDensityScaleChange(float density);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java
index b2f3df60c82b..d7bb667b02a9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java
@@ -352,7 +352,13 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
mTransaction
.addTransactionCommittedListener(
mExecutor,
- this::showBorder)
+ () -> {
+ if (getState() == ENABLING) {
+ // Ensure that we are in the ENABLING process to avoid performing
+ // animation on a null view.
+ mShowBorderRunnable.run();
+ }
+ })
.setPosition(mBorderSurfaceControl, -mBorderOffset, -mBorderOffset)
.setLayer(mBorderSurfaceControl, Integer.MAX_VALUE)
.show(mBorderSurfaceControl)
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index c14d28d1c08d..3b6f8f87a1a8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -174,13 +174,14 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Notify the service to update the magnifier scale only when the progress changed is
- // triggered by user interaction on seekbar
- if (fromUser) {
- final float scale = transformProgressToScale(progress);
- // We don't need to update the persisted scale when the seekbar progress is
- // changing. The update should be triggered when the changing is ended.
- mCallback.onMagnifierScale(scale, /* updatePersistence= */ false);
+ // triggered by user interaction on seekbar.
+ if (!fromUser) {
+ return;
}
+ final float scale = transformProgressToScale(progress);
+ // We don't need to update the persisted scale when the seekbar progress is
+ // changing. The update should be triggered when the changing is ended.
+ mCallback.onMagnifierScale(scale, /* updatePersistence= */ false);
}
@Override
@@ -195,7 +196,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
@Override
public void onUserInteractionFinalized(SeekBar seekBar, @ControlUnitType int control) {
- // Update the Settings persisted scale only when user interaction with seekbar ends
+ // Update the Settings persisted scale only when user interaction with seekbar ends.
final int progress = seekBar.getProgress();
final float scale = transformProgressToScale(progress);
mCallback.onMagnifierScale(scale, /* updatePersistence= */ true);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt b/packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt
index 3f717e282a61..f24c3be0004c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/extradim/ExtraDimDialogManager.kt
@@ -20,6 +20,7 @@ import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.phone.SystemUIDialog
import javax.inject.Inject
@@ -33,7 +34,7 @@ constructor(
private val extraDimDialogDelegateProvider: Provider<ExtraDimDialogDelegate>,
private val mActivityStarter: ActivityStarter,
private val dialogTransitionAnimator: DialogTransitionAnimator,
- private val mainHandler: Handler,
+ @Main private val mainHandler: Handler,
) {
private var dialog: SystemUIDialog? = null
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index 67aa4ff577b8..f8e4bda15d01 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -40,6 +40,7 @@ import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver.AccessibilityButtonMode;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.util.settings.SecureSettings;
@@ -114,7 +115,7 @@ public class AccessibilityFloatingMenuController implements
SecureSettings secureSettings,
DisplayTracker displayTracker,
NavigationModeController navigationModeController,
- Handler handler) {
+ @Main Handler handler) {
mContext = context;
mWindowManager = windowManager;
mViewCaptureAwareWindowManager = viewCaptureAwareWindowManager;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegate.kt
index eaf541d7b559..76b5d823e0b6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegate.kt
@@ -88,7 +88,7 @@ constructor(
dialog.setPositiveButton(
R.string.quick_settings_done,
/* onClick = */ null,
- /* dismissOnClick = */ true
+ /* dismissOnClick = */ true,
)
}
@@ -102,7 +102,7 @@ constructor(
labelArray[i] =
context.resources.getString(
com.android.settingslib.R.string.font_scale_percentage,
- (strEntryValues[i].toFloat() * 100).roundToInt()
+ (strEntryValues[i].toFloat() * 100).roundToInt(),
)
}
seekBarWithIconButtonsView.setProgressStateLabels(labelArray)
@@ -132,7 +132,7 @@ constructor(
override fun onUserInteractionFinalized(
seekBar: SeekBar,
- @ControlUnitType control: Int
+ @ControlUnitType control: Int,
) {
if (control == ControlUnitType.BUTTON) {
// The seekbar progress is changed by icon buttons
@@ -216,7 +216,7 @@ constructor(
!systemSettings.putStringForUser(
Settings.System.FONT_SCALE,
strEntryValues[lastProgress.get()],
- userTracker.userId
+ userTracker.userId,
)
) {
title.post { doneButton.isEnabled = true }
@@ -228,13 +228,13 @@ constructor(
if (
secureSettings.getStringForUser(
Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
- userTracker.userId
+ userTracker.userId,
) != ON
) {
secureSettings.putStringForUser(
Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
ON,
- userTracker.userId
+ userTracker.userId,
)
}
}
@@ -249,7 +249,7 @@ constructor(
title.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
- previewConfigContext.resources.getDimension(R.dimen.dialog_title_text_size)
+ previewConfigContext.resources.getDimension(R.dimen.dialog_title_text_size),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/activity/data/model/AppVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/activity/data/model/AppVisibilityModel.kt
new file mode 100644
index 000000000000..2d21d655561f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/activity/data/model/AppVisibilityModel.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.activity.data.model
+
+/** Describes an app's previous and current visibility to the user. */
+data class AppVisibilityModel(
+ /** True if the app is currently visible to the user and false otherwise. */
+ val isAppCurrentlyVisible: Boolean = false,
+ /**
+ * The last time this app became visible to the user, in
+ * [com.android.systemui.util.time.SystemClock.currentTimeMillis] units. Null if the app hasn't
+ * become visible since the flow started collection.
+ */
+ val lastAppVisibleTime: Long? = null,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/activity/data/repository/ActivityManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/activity/data/repository/ActivityManagerRepository.kt
index 94614b70beda..11831eabf19d 100644
--- a/packages/SystemUI/src/com/android/systemui/activity/data/repository/ActivityManagerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/activity/data/repository/ActivityManagerRepository.kt
@@ -18,9 +18,11 @@ package com.android.systemui.activity.data.repository
import android.app.ActivityManager
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+import com.android.systemui.activity.data.model.AppVisibilityModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.core.Logger
+import com.android.systemui.util.time.SystemClock
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@@ -29,9 +31,23 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.scan
/** Repository for interfacing with [ActivityManager]. */
interface ActivityManagerRepository {
+
+ /**
+ * Given a UID, creates a flow that emits details about when the process with the given UID was
+ * and is visible to the user.
+ *
+ * @param identifyingLogTag a tag identifying who created this flow, used for logging.
+ */
+ fun createAppVisibilityFlow(
+ creationUid: Int,
+ logger: Logger,
+ identifyingLogTag: String,
+ ): Flow<AppVisibilityModel>
+
/**
* Given a UID, creates a flow that emits true when the process with the given UID is visible to
* the user and false otherwise.
@@ -50,8 +66,38 @@ class ActivityManagerRepositoryImpl
@Inject
constructor(
@Background private val backgroundContext: CoroutineContext,
+ private val systemClock: SystemClock,
private val activityManager: ActivityManager,
) : ActivityManagerRepository {
+
+ override fun createAppVisibilityFlow(
+ creationUid: Int,
+ logger: Logger,
+ identifyingLogTag: String,
+ ): Flow<AppVisibilityModel> {
+ return createIsAppVisibleFlow(creationUid, logger, identifyingLogTag)
+ .distinctUntilChanged()
+ .scan(initial = AppVisibilityModel()) {
+ oldState: AppVisibilityModel,
+ newIsVisible: Boolean ->
+ if (newIsVisible) {
+ val lastAppVisibleTime = systemClock.currentTimeMillis()
+ logger.d({ "$str1: Setting lastAppVisibleTime=$long1" }) {
+ str1 = identifyingLogTag
+ long1 = lastAppVisibleTime
+ }
+ AppVisibilityModel(
+ isAppCurrentlyVisible = true,
+ lastAppVisibleTime = lastAppVisibleTime,
+ )
+ } else {
+ // Reset the current status while maintaining the lastAppVisibleTime
+ oldState.copy(isAppCurrentlyVisible = false)
+ }
+ }
+ .distinctUntilChanged()
+ }
+
override fun createIsAppVisibleFlow(
creationUid: Int,
logger: Logger,
diff --git a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
index 11a6cb9334ae..0b578c65e915 100644
--- a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
@@ -23,9 +23,7 @@ import android.window.OnBackInvokedDispatcher
import android.window.WindowOnBackInvokedDispatcher
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.CoreStartable
-import com.android.systemui.Flags.glanceableHubBackAction
import com.android.systemui.Flags.predictiveBackAnimateShade
-import com.android.systemui.communal.domain.interactor.CommunalBackActionInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -52,7 +50,6 @@ constructor(
private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor,
private val shadeBackActionInteractor: ShadeBackActionInteractor,
private val qsController: QuickSettingsController,
- private val communalBackActionInteractor: CommunalBackActionInteractor,
) : CoreStartable {
private var isCallbackRegistered = false
@@ -114,12 +111,6 @@ constructor(
shadeBackActionInteractor.animateCollapseQs(false)
return true
}
- if (glanceableHubBackAction()) {
- if (communalBackActionInteractor.canBeDismissed()) {
- communalBackActionInteractor.onBackPressed()
- return true
- }
- }
if (shouldBackBeHandled()) {
if (shadeBackActionInteractor.canBeCollapsed()) {
// this is the Shade dismiss animation, so make sure QQS closes when it ends.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java
index e5c22677dbcc..1ec7799a0b94 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java
@@ -149,7 +149,7 @@ public class BiometricNotificationService implements CoreStartable {
public BiometricNotificationService(@NonNull @Main Context context,
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
@NonNull KeyguardStateController keyguardStateController,
- @NonNull Handler handler, @NonNull NotificationManager notificationManager,
+ @NonNull @Main Handler handler, @NonNull NotificationManager notificationManager,
@NonNull BiometricNotificationBroadcastReceiver biometricNotificationBroadcastReceiver,
@NonNull Optional<FingerprintReEnrollNotification> fingerprintReEnrollNotification,
@Nullable FingerprintManager fingerprintManager,
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContent.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContent.kt
index 710fde5c2130..c6644562a9cb 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContent.kt
@@ -24,7 +24,7 @@ import androidx.compose.ui.viewinterop.AndroidView
import com.android.systemui.res.R
@Composable
-fun BluetoothDetailsContent(detailsContentViewModel: BluetoothTileDialogViewModel) {
+fun BluetoothDetailsContent(detailsContentViewModel: BluetoothDetailsContentViewModel) {
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { context ->
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt
index d873f41309cc..eebcf0b0f0c1 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt
@@ -62,7 +62,7 @@ data class DeviceItemClick(val deviceItem: DeviceItem, val clickedView: View, va
class BluetoothDetailsContentManager
@AssistedInject
constructor(
- @Assisted private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
+ @Assisted private val initialUiProperties: BluetoothDetailsContentViewModel.UiProperties,
@Assisted private val cachedContentHeight: Int,
@Assisted private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,
@Assisted private val isInDialog: Boolean,
@@ -114,7 +114,7 @@ constructor(
@AssistedFactory
interface Factory {
fun create(
- initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
+ initialUiProperties: BluetoothDetailsContentViewModel.UiProperties,
cachedContentHeight: Int,
dialogCallback: BluetoothTileDialogCallback,
isInDialog: Boolean,
@@ -226,7 +226,7 @@ constructor(
internal fun onBluetoothStateUpdated(
isEnabled: Boolean,
- uiProperties: BluetoothTileDialogViewModel.UiProperties,
+ uiProperties: BluetoothDetailsContentViewModel.UiProperties,
) {
bluetoothToggle.apply {
isChecked = isEnabled
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt
index 308c9d10db93..ff2d9efa1b58 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt
@@ -61,12 +61,9 @@ import kotlinx.coroutines.withContext
/**
* ViewModel for Bluetooth Dialog or Bluetooth Details View after clicking on the Bluetooth QS tile.
- *
- * TODO: b/378513956 Rename this class to BluetoothDetailsContentViewModel, since it's not only used
- * by the dialog view.
*/
@SysUISingleton
-class BluetoothTileDialogViewModel
+class BluetoothDetailsContentViewModel
@Inject
constructor(
private val deviceItemInteractor: DeviceItemInteractor,
@@ -312,7 +309,7 @@ constructor(
return bluetoothDialogDelegateFactory.create(
getUiProperties(),
getCachedContentHeight(),
- this@BluetoothTileDialogViewModel,
+ this@BluetoothDetailsContentViewModel,
{ cancelJob() },
)
}
@@ -321,7 +318,7 @@ constructor(
return bluetoothDetailsContentManagerFactory.create(
getUiProperties(),
getCachedContentHeight(),
- this@BluetoothTileDialogViewModel,
+ this@BluetoothDetailsContentViewModel,
/* isInDialog= */ false,
/* doneButtonCallback= */ fun() {},
)
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt
index 44475318a61e..5863a9385234 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt
@@ -20,7 +20,7 @@ import com.android.systemui.plugins.qs.TileDetailsViewModel
class BluetoothDetailsViewModel(
private val onSettingsClick: () -> Unit,
- val detailsContentViewModel: BluetoothTileDialogViewModel,
+ val detailsContentViewModel: BluetoothDetailsContentViewModel,
) : TileDetailsViewModel() {
override fun clickOnSettingsButton() {
onSettingsClick()
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
index 01be820a2fde..c55f60587527 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
@@ -32,7 +32,7 @@ import dagger.assisted.AssistedInject
class BluetoothTileDialogDelegate
@AssistedInject
constructor(
- @Assisted private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
+ @Assisted private val initialUiProperties: BluetoothDetailsContentViewModel.UiProperties,
@Assisted private val cachedContentHeight: Int,
@Assisted private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,
@Assisted private val dismissListener: Runnable,
@@ -48,7 +48,7 @@ constructor(
@AssistedFactory
interface Factory {
fun create(
- initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
+ initialUiProperties: BluetoothDetailsContentViewModel.UiProperties,
cachedContentHeight: Int,
dialogCallback: BluetoothTileDialogCallback,
dimissListener: Runnable,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt
index e949dc6a1935..3ef50f68cba4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt
@@ -87,6 +87,14 @@ private fun <T> c(old: T, new: T): T {
}
}
+object PatternBouncerConstants {
+ object ColorId {
+ @JvmField val dotColor = colors.materialColorOnSurfaceVariant
+ @JvmField val activatedDotColor = colors.materialColorOnPrimary
+ @JvmField val pathColor = colors.materialColorPrimary
+ }
+}
+
object PinBouncerConstants {
@JvmField
val pinShapes = c(old = R.array.bouncer_pin_shapes, new = R.array.updated_bouncer_pin_shapes)
@@ -126,5 +134,8 @@ object PinBouncerConstants {
@JvmField
val contractionColorInterpolator =
c(old = Interpolators.LINEAR, new = Interpolators.STANDARD)!!
+
+ const val pressedTextScaleX = 1.35f
+ const val normalTextScaleX = 1.0f
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index 434a9ce58c3b..7d8945a5b4a7 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -191,7 +191,6 @@ object KeyguardBouncerViewBinder {
.filter { it == EXPANSION_VISIBLE }
.collect {
securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
- view.announceForAccessibility(securityContainerController.title)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt b/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt
index d4027c029a0a..7c2fc7fe3aee 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt
@@ -17,9 +17,6 @@
package com.android.systemui.common.shared.colors
import android.content.res.Resources
-import android.graphics.Color
-import com.android.internal.graphics.ColorUtils
-import com.android.systemui.res.R
object SurfaceEffectColors {
@JvmStatic
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
index 82bce0b5338a..257a5a4d9061 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
@@ -286,7 +286,8 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
/**
* Notification that the user interaction with SeekBarWithIconButtonsView is finalized. This
- * would be triggered after user ends dragging on the slider or clicks icon buttons.
+ * would be triggered after user ends dragging on the slider or clicks icon buttons. This is
+ * not called if the progress change was not initiated by the user.
*
* @param seekBar The SeekBar in which the user ends interaction with
* @param control The last user interacted control unit. It would be
@@ -318,10 +319,14 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
seekBar, OnSeekBarWithIconButtonsChangeListener.ControlUnitType.BUTTON);
} else {
mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
- if (!mSeekByTouch) {
+ if (!mSeekByTouch && fromUser) {
// Accessibility users could change the progress of the seekbar without
- // touching the seekbar or clicking the buttons. We will consider the
- // interaction has finished in this case.
+ // touching the seekbar or clicking the buttons. In this, {@code fromUser}
+ // will be true, and we will consider the interaction to be finished.
+ // The seekbar progress could be changed when {@code fromUser} is false
+ // when magnification scale is set by pinch-to-zoom, keyboard control, or
+ // other services. In this case, we don't need to take finalized actions
+ // for the progress change.
mOnSeekBarChangeListener.onUserInteractionFinalized(
seekBar,
OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER);
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt
index 7abad1448318..18d461add52b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalBackupRestoreStartable.kt
@@ -29,6 +29,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.widgets.CommunalWidgetModule
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
@@ -43,7 +44,7 @@ constructor(
private val communalInteractor: CommunalInteractor,
@CommunalLog logBuffer: LogBuffer,
private val secureSettings: SecureSettings,
- handler: Handler,
+ @Main handler: Handler,
) : CoreStartable, BroadcastReceiver() {
private val logger = Logger(logBuffer, TAG)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 4f956fc802e4..e36e85565293 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -19,8 +19,6 @@ package com.android.systemui.communal
import android.os.UserHandle
import android.provider.Settings
import com.android.app.tracing.coroutines.launchTraced as launch
-import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.TransitionKey
import com.android.internal.logging.UiEventLogger
import com.android.systemui.CoreStartable
import com.android.systemui.communal.domain.interactor.CommunalInteractor
@@ -31,25 +29,16 @@ import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalScenes.isCommunal
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dock.DockManager
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.statusbar.NotificationShadeWindowController
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.util.kotlin.emitOnStart
-import com.android.systemui.util.kotlin.getValue
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import com.android.systemui.util.settings.SystemSettings
-import java.util.Optional
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
-import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -68,16 +57,12 @@ import kotlinx.coroutines.withContext
class CommunalSceneStartable
@Inject
constructor(
- private val dockManager: DockManager,
private val communalInteractor: CommunalInteractor,
private val communalSettingsInteractor: CommunalSettingsInteractor,
private val communalSceneInteractor: CommunalSceneInteractor,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val keyguardInteractor: KeyguardInteractor,
private val systemSettings: SystemSettings,
- centralSurfacesOpt: Optional<CentralSurfaces>,
private val notificationShadeWindowController: NotificationShadeWindowController,
- @Application private val applicationScope: CoroutineScope,
@Background private val bgScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
private val uiEventLogger: UiEventLogger,
@@ -88,75 +73,85 @@ constructor(
private var isDreaming: Boolean = false
- private val centralSurfaces: CentralSurfaces? by centralSurfacesOpt
-
override fun start() {
if (!communalSettingsInteractor.isCommunalFlagEnabled()) {
return
}
- systemSettings
- .observerFlow(Settings.System.SCREEN_OFF_TIMEOUT)
- // Read the setting value on start.
- .emitOnStart()
- .onEach {
- screenTimeout =
- systemSettings.getIntForUser(
- Settings.System.SCREEN_OFF_TIMEOUT,
- DEFAULT_SCREEN_TIMEOUT,
- UserHandle.USER_CURRENT,
- )
- }
- .launchIn(bgScope)
-
- // The hub mode timeout should start as soon as the user enters hub mode. At the end of the
- // timer, if the device is dreaming, hub mode should closed and reveal the dream. If the
- // dream is not running, nothing will happen. However if the dream starts again underneath
- // hub mode after the initial timeout expires, such as if the device is docked or the dream
- // app is updated by the Play store, a new timeout should be started.
bgScope.launch {
- combine(
- communalSceneInteractor.currentScene,
- // Emit a value on start so the combine starts.
- communalInteractor.userActivity.emitOnStart(),
- ) { scene, _ ->
- // Only timeout if we're on the hub is open.
- scene.isCommunal()
- }
- .collectLatest { shouldTimeout ->
- cancelHubTimeout()
- if (shouldTimeout) {
- startHubTimeout()
- }
+ communalSceneInteractor.isIdleOnCommunal.collectLatest {
+ withContext(mainDispatcher) {
+ notificationShadeWindowController.setGlanceableHubShowing(it)
}
+ }
}
- bgScope.launch {
- keyguardInteractor.isDreaming
- .sample(communalSceneInteractor.currentScene, ::Pair)
- .collectLatest { (isDreaming, scene) ->
- this@CommunalSceneStartable.isDreaming = isDreaming
- if (scene.isCommunal() && isDreaming && timeoutJob == null) {
- // If dreaming starts after timeout has expired, ex. if dream restarts under
- // the hub, wait for IS_ABLE_TO_DREAM_DELAY_MS and then close the hub. The
- // delay is necessary so the KeyguardInteractor.isAbleToDream flow passes
- // through that same amount of delay and publishes a new value which is then
- // picked up by the HomeSceneFamilyResolver such that the next call to
- // SceneInteractor.changeScene(Home) will resolve "Home" to "Dream".
- delay(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
- communalSceneInteractor.changeScene(
- CommunalScenes.Blank,
- "dream started after timeout",
+
+ // In V2, the timeout is handled by PowerManagerService since we no longer keep the dream
+ // active underneath the hub.
+ if (!communalSettingsInteractor.isV2FlagEnabled()) {
+ systemSettings
+ .observerFlow(Settings.System.SCREEN_OFF_TIMEOUT)
+ // Read the setting value on start.
+ .emitOnStart()
+ .onEach {
+ screenTimeout =
+ systemSettings.getIntForUser(
+ Settings.System.SCREEN_OFF_TIMEOUT,
+ DEFAULT_SCREEN_TIMEOUT,
+ UserHandle.USER_CURRENT,
)
- uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT)
- }
}
- }
+ .launchIn(bgScope)
- bgScope.launch {
- communalSceneInteractor.isIdleOnCommunal.collectLatest {
- withContext(mainDispatcher) {
- notificationShadeWindowController.setGlanceableHubShowing(it)
- }
+ // The hub mode timeout should start as soon as the user enters hub mode. At the end of
+ // the
+ // timer, if the device is dreaming, hub mode should closed and reveal the dream. If the
+ // dream is not running, nothing will happen. However if the dream starts again
+ // underneath
+ // hub mode after the initial timeout expires, such as if the device is docked or the
+ // dream
+ // app is updated by the Play store, a new timeout should be started.
+ bgScope.launch {
+ combine(
+ communalSceneInteractor.currentScene,
+ // Emit a value on start so the combine starts.
+ communalInteractor.userActivity.emitOnStart(),
+ ) { scene, _ ->
+ // Only timeout if we're on the hub is open.
+ scene.isCommunal()
+ }
+ .collectLatest { shouldTimeout ->
+ cancelHubTimeout()
+ if (shouldTimeout) {
+ startHubTimeout()
+ }
+ }
+ }
+
+ bgScope.launch {
+ keyguardInteractor.isDreaming
+ .sample(communalSceneInteractor.currentScene, ::Pair)
+ .collectLatest { (isDreaming, scene) ->
+ this@CommunalSceneStartable.isDreaming = isDreaming
+ if (scene.isCommunal() && isDreaming && timeoutJob == null) {
+ // If dreaming starts after timeout has expired, ex. if dream restarts
+ // under
+ // the hub, wait for IS_ABLE_TO_DREAM_DELAY_MS and then close the hub.
+ // The
+ // delay is necessary so the KeyguardInteractor.isAbleToDream flow
+ // passes
+ // through that same amount of delay and publishes a new value which is
+ // then
+ // picked up by the HomeSceneFamilyResolver such that the next call to
+ // SceneInteractor.changeScene(Home) will resolve "Home" to "Dream".
+ delay(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
+ communalSceneInteractor.changeScene(
+ CommunalScenes.Blank,
+ "dream started after timeout",
+ )
+ uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT)
+ }
+ }
}
}
}
@@ -187,49 +182,7 @@ constructor(
}
}
- private suspend fun determineSceneAfterTransition(
- lastStartedTransition: TransitionStep
- ): Pair<SceneKey, TransitionKey>? {
- val to = lastStartedTransition.to
- val from = lastStartedTransition.from
- val docked = dockManager.isDocked
- val launchingActivityOverLockscreen =
- centralSurfaces?.isLaunchingActivityOverLockscreen ?: false
-
- return when {
- to == KeyguardState.OCCLUDED && !launchingActivityOverLockscreen -> {
- // Hide communal when an activity is started on keyguard, to ensure the activity
- // underneath the hub is shown. When launching activities over lockscreen, we only
- // change scenes once the activity launch animation is finished, so avoid
- // changing the scene here.
- Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
- }
- to == KeyguardState.GLANCEABLE_HUB && from == KeyguardState.OCCLUDED -> {
- // When transitioning to the hub from an occluded state, fade out the hub without
- // doing any translation.
- Pair(CommunalScenes.Communal, CommunalTransitionKeys.SimpleFade)
- }
- // Transitioning to Blank scene when entering the edit mode will be handled separately
- // with custom animations.
- to == KeyguardState.GONE && !communalInteractor.editModeOpen.value ->
- Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
- !docked && !KeyguardState.deviceIsAwakeInState(to) -> {
- // If the user taps the screen and wakes the device within this timeout, we don't
- // want to dismiss the hub
- delay(AWAKE_DEBOUNCE_DELAY)
- Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
- }
- from == KeyguardState.DOZING && to == KeyguardState.GLANCEABLE_HUB -> {
- // Make sure the communal hub is showing when transitioning from dozing to hub.
- Pair(CommunalScenes.Communal, CommunalTransitionKeys.SimpleFade)
- }
- else -> null
- }
- }
-
companion object {
- val AWAKE_DEBOUNCE_DELAY = 5.seconds
- val DOCK_DEBOUNCE_DELAY = 1.seconds
val DEFAULT_SCREEN_TIMEOUT = 15000
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt
index 0a9bd4214a12..bf4445ba18db 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt
@@ -151,5 +151,7 @@ constructor(
override fun instantlyShowOverlay(overlay: OverlayKey) = Unit
override fun instantlyHideOverlay(overlay: OverlayKey) = Unit
+
+ override fun freezeAndAnimateToCurrentState() = Unit
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractor.kt
deleted file mode 100644
index 2ccf96abff79..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractor.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.communal.domain.interactor
-
-import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.scene.shared.model.Scenes
-import javax.inject.Inject
-
-/**
- * {@link CommunalBackActionInteractor} is responsible for handling back gestures on the glanceable
- * hub. When invoked SystemUI should navigate back to the lockscreen.
- */
-@SysUISingleton
-class CommunalBackActionInteractor
-@Inject
-constructor(
- private val communalInteractor: CommunalInteractor,
- private val communalSceneInteractor: CommunalSceneInteractor,
- private val sceneInteractor: SceneInteractor,
-) {
- fun canBeDismissed(): Boolean {
- return communalInteractor.isCommunalShowing.value
- }
-
- fun onBackPressed() {
- if (SceneContainerFlag.isEnabled) {
- // TODO(b/384610333): Properly determine whether to go to dream or lockscreen on back.
- sceneInteractor.changeScene(
- toScene = Scenes.Lockscreen,
- loggingReason = "CommunalBackActionInteractor",
- )
- } else {
- communalSceneInteractor.changeScene(
- newScene = CommunalScenes.Blank,
- loggingReason = "CommunalBackActionInteractor",
- )
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 6dab32a66c94..564628d3f52f 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -327,7 +327,7 @@ constructor(
* use [isIdleOnCommunal].
*/
// TODO(b/323215860): rename to something more appropriate after cleaning up usages
- val isCommunalShowing: StateFlow<Boolean> =
+ val isCommunalShowing: Flow<Boolean> =
flow { emit(SceneContainerFlag.isEnabled) }
.flatMapLatest { sceneContainerEnabled ->
if (sceneContainerEnabled) {
@@ -345,10 +345,10 @@ constructor(
columnName = "isCommunalShowing",
initialValue = false,
)
- .stateIn(
+ .shareIn(
scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = false,
+ started = SharingStarted.WhileSubscribed(),
+ replay = 1,
)
/**
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt
index 740555f40dea..477b87119563 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt
@@ -32,6 +32,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.util.kotlin.pairwise
import java.util.UUID
@@ -65,6 +66,7 @@ constructor(
@Application private val applicationScope: CoroutineScope,
private val sceneInteractor: CommunalSceneInteractor,
private val repository: CommunalSceneTransitionRepository,
+ private val powerInteractor: PowerInteractor,
keyguardInteractor: KeyguardInteractor,
) : CoreStartable, CommunalSceneInteractor.OnSceneAboutToChangeListener {
@@ -88,12 +90,15 @@ constructor(
combine(
// Don't use delayed dreaming signal as otherwise we might go to occluded or lock
// screen when closing hub if dream just started under the hub.
+ powerInteractor.isAsleep,
keyguardInteractor.isDreamingWithOverlay,
keyguardInteractor.isKeyguardOccluded,
keyguardInteractor.isKeyguardGoingAway,
keyguardInteractor.isKeyguardShowing,
- ) { dreaming, occluded, keyguardGoingAway, keyguardShowing ->
- if (keyguardGoingAway) {
+ ) { asleep, dreaming, occluded, keyguardGoingAway, keyguardShowing ->
+ if (asleep) {
+ KeyguardState.DOZING
+ } else if (keyguardGoingAway) {
KeyguardState.GONE
} else if (occluded && !dreaming) {
KeyguardState.OCCLUDED
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
index ca49de3b1510..a84c45732169 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
@@ -31,4 +31,6 @@ object CommunalTransitionKeys {
val ToEditMode = TransitionKey("ToEditMode")
/** Transition to the glanceable hub after exiting edit mode */
val FromEditMode = TransitionKey("FromEditMode")
+ /** Swipes the glanceable hub in/out of view */
+ val Swipe = TransitionKey("Swipe")
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 2169881d11c5..cce1ae1a2947 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -359,7 +359,13 @@ constructor(
/** See [CommunalSettingsInteractor.isV2FlagEnabled] */
fun v2FlagEnabled(): Boolean = communalSettingsInteractor.isV2FlagEnabled()
- fun swipeToHubEnabled(): Boolean = swipeToHub
+ val swipeToHubEnabled: StateFlow<Boolean> by lazy {
+ if (v2FlagEnabled()) {
+ communalInteractor.shouldShowCommunal
+ } else {
+ MutableStateFlow(swipeToHub)
+ }
+ }
companion object {
const val POPUP_AUTO_HIDE_TIMEOUT_MS = 12000L
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 8e0beda9eff7..7354f4096801 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -212,13 +212,6 @@ public class FrameworkServicesModule {
return new UserScopedServiceImpl<>(context, CaptioningManager.class);
}
- /** */
- @Provides
- @Singleton
- public Choreographer providesChoreographer() {
- return Choreographer.getInstance();
- }
-
@Provides
@Singleton
static ColorDisplayManager provideColorDisplayManager(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 8bff090959ab..3c68e3a09f02 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -74,7 +74,6 @@ import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.dagger.CentralSurfacesModule;
import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule;
-import com.android.systemui.statusbar.notification.dagger.NotificationStackModule;
import com.android.systemui.statusbar.notification.dagger.ReferenceNotificationsModule;
import com.android.systemui.statusbar.notification.headsup.HeadsUpModule;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -170,7 +169,6 @@ import javax.inject.Named;
WallpaperModule.class,
ShortcutHelperModule.class,
ContextualEducationModule.class,
- NotificationStackModule.class,
})
public abstract class ReferenceSystemUIModule {
diff --git a/packages/SystemUI/src/com/android/systemui/decor/ScreenDecorCommand.kt b/packages/SystemUI/src/com/android/systemui/decor/ScreenDecorCommand.kt
index fa1d898de850..c5d5ca26b14c 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/ScreenDecorCommand.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/ScreenDecorCommand.kt
@@ -53,6 +53,14 @@ class ScreenDecorCommand(
val roundedBottom: RoundedCornerSubCommand? by
subCommand(RoundedCornerSubCommand("rounded-bottom"))
+ val faceAuthScreen: Int? by
+ param(
+ longName = "faceAuthScreen",
+ description =
+ "Specify a screen to show face auth animation. 0:outer(default screen), 1:inner",
+ valueParser = Type.Int,
+ )
+
override fun execute(pw: PrintWriter) {
callback.onExecute(this, pw)
}
@@ -61,6 +69,7 @@ class ScreenDecorCommand(
return "ScreenDecorCommand(" +
"debug=$debug, " +
"color=$color, " +
+ "faceAuthScreen=$faceAuthScreen, " +
"roundedTop=$roundedTop, " +
"roundedBottom=$roundedBottom)"
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index abc810afca98..6b762bacb440 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -40,6 +40,7 @@ import android.util.IndentingPrintWriter;
import android.view.Display;
import com.android.internal.R;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.dagger.BrightnessSensor;
import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.doze.dagger.WrappedService;
@@ -118,7 +119,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
@WrappedService DozeMachine.Service service,
AsyncSensorManager sensorManager,
@BrightnessSensor Optional<Sensor>[] lightSensorOptional,
- DozeHost host, Handler handler,
+ DozeHost host, @Main Handler handler,
AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
WakefulnessLifecycle wakefulnessLifecycle,
DozeParameters dozeParameters,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index a56a63c0b104..3132ec2b98e3 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -53,7 +53,6 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.Flags;
import com.android.systemui.ambient.touch.TouchHandler;
import com.android.systemui.ambient.touch.TouchMonitor;
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent;
@@ -211,7 +210,6 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mCommunalVisible = communalVisible;
updateLifecycleStateLocked();
- updateGestureBlockingLocked();
});
}
};
@@ -594,8 +592,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
private void updateGestureBlockingLocked() {
final boolean shouldBlock = mStarted && !mShadeExpanded && !mBouncerShowing
- && !isDreamInPreviewMode()
- && !(Flags.glanceableHubBackAction() && mCommunalVisible);
+ && !isDreamInPreviewMode();
if (shouldBlock) {
mGestureInteractor.addGestureBlockedMatcher(DREAM_TYPE_MATCHER,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/service/TaskFragmentComponent.kt b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/service/TaskFragmentComponent.kt
index 67de30c8fa5c..c81583864d45 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/service/TaskFragmentComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/service/TaskFragmentComponent.kt
@@ -83,7 +83,8 @@ constructor(
resultT.addTaskFragmentOperation(
fragmentToken,
TaskFragmentOperation.Builder(
- TaskFragmentOperation.OP_TYPE_REORDER_TO_TOP_OF_TASK
+ TaskFragmentOperation
+ .OP_TYPE_PRIVILEGED_REORDER_TO_TOP_OF_TASK
)
.build(),
)
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index ebe228dab05a..26501596aa1a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -45,7 +45,6 @@ class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, ha
// Internal notification backend dependencies
crossAppPoliteNotifications dependsOn politeNotifications
vibrateWhileUnlockedToken dependsOn politeNotifications
- modesUi dependsOn modesApi
// Internal notification frontend dependencies
NotificationAvalancheSuppression.token dependsOn VisualInterruptionRefactor.token
@@ -71,9 +70,6 @@ class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, ha
private inline val modesUi
get() = FlagToken(android.app.Flags.FLAG_MODES_UI, android.app.Flags.modesUi())
- private inline val modesApi
- get() = FlagToken(android.app.Flags.FLAG_MODES_API, android.app.Flags.modesApi())
-
private inline val communalHub
get() = FlagToken(FLAG_COMMUNAL_HUB, communalHub())
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
index b712fdeaf623..0d57a57c3416 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
@@ -102,10 +102,9 @@ constructor(
}
// This flow is used by the notification updater once an initial notification is launched. It
- // listens to the device connection changes for both keyboard and touchpad. When either of the
- // device is disconnected, resolve the tutorial type base on the latest connection state.
- // Dropping the initial state because it's the existing notification. Filtering out BOTH because
- // we only care about disconnections.
+ // listens to the changes of keyboard and touchpad connection and resolve the tutorial type base
+ // on the latest connection state.
+ // Dropping the initial state because it represents the existing notification.
val tutorialTypeUpdates: Flow<TutorialType> =
keyboardRepository.isAnyKeyboardConnected
.combine(touchpadRepository.isAnyTouchpadConnected, ::Pair)
@@ -118,7 +117,6 @@ constructor(
}
}
.drop(1)
- .filter { it != TutorialType.BOTH }
private suspend fun waitForDeviceConnection(deviceType: DeviceType) =
isAnyDeviceConnected[deviceType]!!.filter { it }.first()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
index 464201f6ec12..b787fc2a2b17 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
@@ -19,6 +19,7 @@ package com.android.systemui.keyboard.shortcut.data.source
import android.content.Context
import android.content.res.Resources
import android.view.KeyEvent.KEYCODE_D
+import android.view.KeyEvent.KEYCODE_DPAD_DOWN
import android.view.KeyEvent.KEYCODE_DPAD_LEFT
import android.view.KeyEvent.KEYCODE_DPAD_RIGHT
import android.view.KeyEvent.KEYCODE_DPAD_UP
@@ -73,6 +74,15 @@ constructor(@Main private val resources: Resources, @Application private val con
command(META_META_ON or META_CTRL_ON, KEYCODE_DPAD_UP)
}
)
+ if (DesktopModeStatus.canEnterDesktopMode(context)) {
+ // Switch to desktop view
+ // - Meta + Ctrl + Down arrow
+ add(
+ shortcutInfo(resources.getString(R.string.system_multitasking_desktop_view)) {
+ command(META_META_ON or META_CTRL_ON, KEYCODE_DPAD_DOWN)
+ }
+ )
+ }
if (enableMoveToNextDisplayShortcut()) {
// Move a window to the next display:
// - Meta + Ctrl + D
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index caf0fd4450fc..efa9c21f96b4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard;
+import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT;
import static android.provider.Settings.System.LOCKSCREEN_SOUNDS_ENABLED;
@@ -75,6 +76,7 @@ import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -192,6 +194,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -282,6 +286,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private static final int SYSTEM_READY = 18;
private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
private static final int BOOT_INTERACTOR = 20;
+ private static final int BEFORE_USER_SWITCHING = 21;
+ private static final int USER_SWITCHING = 22;
+ private static final int USER_SWITCH_COMPLETE = 23;
/** Enum for reasons behind updating wakeAndUnlock state. */
@Retention(RetentionPolicy.SOURCE)
@@ -299,6 +306,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
int WAKE_AND_UNLOCK = 3;
}
+ private final List<LockNowCallback> mLockNowCallbacks = new ArrayList<>();
+
/**
* The default amount of time we stay awake (used for all key input)
*/
@@ -357,13 +366,18 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthController;
private final Lazy<ShadeController> mShadeController;
private final Lazy<CommunalSceneInteractor> mCommunalSceneInteractor;
+ /*
+ * Records the user id on request to go away, for validation when WM calls back to start the
+ * exit animation.
+ */
+ private int mGoingAwayRequestedForUserId = -1;
+
private boolean mSystemReady;
private boolean mBootCompleted;
private boolean mBootSendUserPresent;
private boolean mShuttingDown;
private boolean mDozing;
private boolean mAnimatingScreenOff;
- private boolean mIgnoreDismiss;
private final Context mContext;
private final FalsingCollector mFalsingCollector;
@@ -626,41 +640,92 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
};
- KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
+ @VisibleForTesting
+ protected UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() {
@Override
- public void onKeyguardVisibilityChanged(boolean visible) {
- synchronized (KeyguardViewMediator.this) {
- if (!visible && mPendingPinLock) {
- Log.i(TAG, "PIN lock requested, starting keyguard");
+ public void onBeforeUserSwitching(int newUser, @NonNull Runnable resultCallback) {
+ mHandler.sendMessage(mHandler.obtainMessage(BEFORE_USER_SWITCHING,
+ newUser, 0, resultCallback));
+ }
- // Bring the keyguard back in order to show the PIN lock
- mPendingPinLock = false;
- doKeyguardLocked(null);
- }
- }
+ @Override
+ public void onUserChanging(int newUser, @NonNull Context userContext,
+ @NonNull Runnable resultCallback) {
+ mHandler.sendMessage(mHandler.obtainMessage(USER_SWITCHING,
+ newUser, 0, resultCallback));
}
@Override
- public void onUserSwitching(int userId) {
- Log.d(TAG, String.format("onUserSwitching %d", userId));
- synchronized (KeyguardViewMediator.this) {
- mIgnoreDismiss = true;
- notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
- resetKeyguardDonePendingLocked();
+ public void onUserChanged(int newUser, Context userContext) {
+ mHandler.sendMessage(mHandler.obtainMessage(USER_SWITCH_COMPLETE,
+ newUser, 0));
+ }
+ };
+
+ /**
+ * Handle {@link #BEFORE_USER_SWITCHING}
+ */
+ @VisibleForTesting
+ void handleBeforeUserSwitching(int userId, Runnable resultCallback) {
+ Log.d(TAG, String.format("onBeforeUserSwitching %d", userId));
+ synchronized (KeyguardViewMediator.this) {
+ mHandler.removeMessages(DISMISS);
+ notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
+ resetKeyguardDonePendingLocked();
+ adjustStatusBarLocked();
+ mKeyguardStateController.notifyKeyguardGoingAway(false);
+ if (mLockPatternUtils.isSecure(userId) && !mShowing) {
+ doKeyguardLocked(null);
+ } else {
resetStateLocked();
- adjustStatusBarLocked();
}
+ resultCallback.run();
}
+ }
- @Override
- public void onUserSwitchComplete(int userId) {
- mIgnoreDismiss = false;
- Log.d(TAG, String.format("onUserSwitchComplete %d", userId));
+ /**
+ * Handle {@link #USER_SWITCHING}
+ */
+ @VisibleForTesting
+ void handleUserSwitching(int userId, Runnable resultCallback) {
+ Log.d(TAG, String.format("onUserSwitching %d", userId));
+ synchronized (KeyguardViewMediator.this) {
+ if (!mLockPatternUtils.isSecure(userId)) {
+ dismiss(null, null);
+ }
+ resultCallback.run();
+ }
+ }
+
+ /**
+ * Handle {@link #USER_SWITCH_COMPLETE}
+ */
+ @VisibleForTesting
+ void handleUserSwitchComplete(int userId) {
+ Log.d(TAG, String.format("onUserSwitchComplete %d", userId));
+ // Calling dismiss on a secure user will show the bouncer
+ if (mLockPatternUtils.isSecure(userId)) {
// We are calling dismiss with a delay as there are race conditions in some scenarios
// caused by async layout listeners
mHandler.postDelayed(() -> dismiss(null /* callback */, null /* message */), 500);
}
+ }
+
+ KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean visible) {
+ synchronized (KeyguardViewMediator.this) {
+ if (!visible && mPendingPinLock) {
+ Log.i(TAG, "PIN lock requested, starting keyguard");
+
+ // Bring the keyguard back in order to show the PIN lock
+ mPendingPinLock = false;
+ doKeyguardLocked(null);
+ }
+ }
+ }
@Override
public void onDeviceProvisioned() {
@@ -1671,7 +1736,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
com.android.internal.R.anim.lock_screen_behind_enter);
mWorkLockController = new WorkLockActivityController(mContext, mUserTracker);
-
+ mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
+ // start() can be invoked in the middle of user switching, so check for this state and issue
+ // the call manually as that important event was missed.
+ if (mUserTracker.isUserSwitching()) {
+ handleBeforeUserSwitching(mUserTracker.getUserId(), () -> {});
+ handleUserSwitching(mUserTracker.getUserId(), () -> {});
+ }
mJavaAdapter.alwaysCollectFlow(
mWallpaperRepository.getWallpaperSupportsAmbientMode(),
this::setWallpaperSupportsAmbientMode);
@@ -1720,7 +1791,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// System ready can be invoked in the middle of user switching, so check for this state
// and issue the call manually as that important event was missed.
if (mUserTracker.isUserSwitching()) {
- mUpdateCallback.onUserSwitching(mUserTracker.getUserId());
+ mUserChangedCallback.onUserChanging(mUserTracker.getUserId(), mContext, () -> {});
}
}
// Most services aren't available until the system reaches the ready state, so we
@@ -2361,12 +2432,23 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mCommunalSceneInteractor.get().showHubFromPowerButton();
}
+ int currentUserId = mSelectedUserInteractor.getSelectedUserId();
+ if (options != null && options.getBinder(LOCK_ON_USER_SWITCH_CALLBACK) != null) {
+ LockNowCallback callback = new LockNowCallback(currentUserId,
+ IRemoteCallback.Stub.asInterface(
+ options.getBinder(LOCK_ON_USER_SWITCH_CALLBACK)));
+ synchronized (mLockNowCallbacks) {
+ mLockNowCallbacks.add(callback);
+ }
+ Log.d(TAG, "LockNowCallback required for user: " + callback.mUserId);
+ }
+
// if another app is disabling us, don't show
if (!mExternallyEnabled
&& !mLockPatternUtils.isUserInLockdown(
mSelectedUserInteractor.getSelectedUserId())) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
-
+ notifyLockNowCallback();
mNeedToReshowWhenReenabled = true;
return;
}
@@ -2384,6 +2466,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// We're removing "reset" in the refactor - "resetting" the views will happen
// as a reaction to the root cause of the "reset" signal.
if (KeyguardWmStateRefactor.isEnabled()) {
+ notifyLockNowCallback();
return;
}
@@ -2396,6 +2479,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
+ "previously hiding. It should be safe to short-circuit "
+ "here.");
resetStateLocked(/* hideBouncer= */ false);
+ notifyLockNowCallback();
return;
}
} else {
@@ -2422,6 +2506,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
Log.d(TAG, "doKeyguard: not showing because device isn't provisioned and the sim is"
+ " not locked or missing");
}
+ notifyLockNowCallback();
return;
}
@@ -2429,6 +2514,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
if (mLockPatternUtils.isLockScreenDisabled(mSelectedUserInteractor.getSelectedUserId())
&& !lockedOrMissing && !forceShow) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
+ notifyLockNowCallback();
return;
}
@@ -2476,11 +2562,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
public void dismiss(IKeyguardDismissCallback callback, CharSequence message) {
- if (mIgnoreDismiss) {
- android.util.Log.i(TAG, "Ignoring request to dismiss (user switch in progress?)");
- return;
- }
-
if (mKeyguardStateController.isKeyguardGoingAway()) {
Log.i(TAG, "Ignoring dismiss because we're already going away.");
return;
@@ -2498,7 +2579,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
private void resetStateLocked(boolean hideBouncer) {
- if (DEBUG) Log.e(TAG, "resetStateLocked");
+ if (DEBUG) Log.d(TAG, "resetStateLocked");
Message msg = mHandler.obtainMessage(RESET, hideBouncer ? 1 : 0, 0);
mHandler.sendMessage(msg);
}
@@ -2746,6 +2827,18 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
message = "BOOT_INTERACTOR";
handleBootInteractor();
break;
+ case BEFORE_USER_SWITCHING:
+ message = "BEFORE_USER_SWITCHING";
+ handleBeforeUserSwitching(msg.arg1, (Runnable) msg.obj);
+ break;
+ case USER_SWITCHING:
+ message = "USER_SWITCHING";
+ handleUserSwitching(msg.arg1, (Runnable) msg.obj);
+ break;
+ case USER_SWITCH_COMPLETE:
+ message = "USER_SWITCH_COMPLETE";
+ handleUserSwitchComplete(msg.arg1);
+ break;
}
Log.d(TAG, "KeyguardViewMediator queue processing message: " + message);
}
@@ -2887,6 +2980,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mUiBgExecutor.execute(() -> {
Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ", "
+ reason + ")");
+ if (showing) {
+ notifyLockNowCallback();
+ }
if (KeyguardWmStateRefactor.isEnabled()) {
// Handled in WmLockscreenVisibilityManager if flag is enabled.
@@ -2931,6 +3027,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
synchronized (KeyguardViewMediator.this) {
if (!mSystemReady) {
if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
+ notifyLockNowCallback();
return;
}
if (DEBUG) Log.d(TAG, "handleShow");
@@ -2989,12 +3086,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
}
- private final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
+ final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
@SuppressLint("MissingPermission")
@Override
public void run() {
Trace.beginSection("KeyguardViewMediator.mKeyGuardGoingAwayRunnable");
- Log.d(TAG, "keyguardGoingAwayRunnable");
mKeyguardViewControllerLazy.get().keyguardGoingAway();
int flags = 0;
@@ -3031,6 +3127,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// Handled in WmLockscreenVisibilityManager if flag is enabled.
if (!KeyguardWmStateRefactor.isEnabled()) {
+ mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
+ Log.d(TAG, "keyguardGoingAway requested for userId: "
+ + mGoingAwayRequestedForUserId);
+
// Don't actually hide the Keyguard at the moment, wait for window manager
// until it tells us it's safe to do so with startKeyguardExitAnimation.
// Posting to mUiOffloadThread to ensure that calls to ActivityTaskManager
@@ -3169,6 +3269,30 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime
+ " fadeoutDuration=" + fadeoutDuration);
+ int currentUserId = mSelectedUserInteractor.getSelectedUserId();
+ if (!KeyguardWmStateRefactor.isEnabled() && mGoingAwayRequestedForUserId != currentUserId) {
+ Log.e(TAG, "Not executing handleStartKeyguardExitAnimationInner() due to userId "
+ + "mismatch. Requested: " + mGoingAwayRequestedForUserId + ", current: "
+ + currentUserId);
+ if (finishedCallback != null) {
+ // There will not execute animation, send a finish callback to ensure the remote
+ // animation won't hang there.
+ try {
+ finishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call onAnimationFinished", e);
+ }
+ }
+ mHiding = false;
+ if (mLockPatternUtils.isSecure(currentUserId)) {
+ doKeyguardLocked(null);
+ } else {
+ resetStateLocked();
+ dismiss(null, null);
+ }
+ return;
+ }
+
synchronized (KeyguardViewMediator.this) {
mIsKeyguardExitAnimationCanceled = false;
// Tell ActivityManager that we canceled the keyguard animation if
@@ -3413,6 +3537,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
* app transition before finishing the current RemoteAnimation, or the keyguard being re-shown).
*/
private void handleCancelKeyguardExitAnimation() {
+ if (!KeyguardWmStateRefactor.isEnabled()
+ && mGoingAwayRequestedForUserId != mSelectedUserInteractor.getSelectedUserId()) {
+ Log.e(TAG, "Setting pendingLock = true due to userId mismatch. Requested: "
+ + mGoingAwayRequestedForUserId + ", current: "
+ + mSelectedUserInteractor.getSelectedUserId());
+ setPendingLock(true);
+ }
if (mPendingLock) {
Log.d(TAG, "#handleCancelKeyguardExitAnimation: keyguard exit animation cancelled. "
+ "There's a pending lock, so we were cancelled because the device was locked "
@@ -3513,6 +3644,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mSurfaceBehindRemoteAnimationRequested = true;
if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS && !KeyguardWmStateRefactor.isEnabled()) {
+ mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */);
return;
}
@@ -3533,6 +3665,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
if (!KeyguardWmStateRefactor.isEnabled()) {
// Handled in WmLockscreenVisibilityManager.
+ mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
+ Log.d(TAG, "keyguardGoingAway requested for userId: "
+ + mGoingAwayRequestedForUserId);
mActivityTaskManagerService.keyguardGoingAway(flags);
}
} catch (RemoteException e) {
@@ -3988,6 +4123,29 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mUiBgExecutor.execute(mTrustManager::reportKeyguardShowingChanged);
}
+ private void notifyLockNowCallback() {
+ List<LockNowCallback> callbacks;
+ synchronized (mLockNowCallbacks) {
+ callbacks = new ArrayList<LockNowCallback>(mLockNowCallbacks);
+ mLockNowCallbacks.clear();
+ }
+ Iterator<LockNowCallback> iter = callbacks.listIterator();
+ while (iter.hasNext()) {
+ LockNowCallback callback = iter.next();
+ iter.remove();
+ if (callback.mUserId != mSelectedUserInteractor.getSelectedUserId()) {
+ Log.i(TAG, "Not notifying lockNowCallback due to user mismatch");
+ continue;
+ }
+ Log.i(TAG, "Notifying lockNowCallback");
+ try {
+ callback.mRemoteCallback.sendResult(null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not issue LockNowCallback sendResult", e);
+ }
+ }
+ }
+
private void notifyTrustedChangedLocked(boolean trusted) {
int size = mKeyguardStateCallbacks.size();
for (int i = size - 1; i >= 0; i--) {
@@ -4152,4 +4310,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
};
}
+
+ private class LockNowCallback {
+ final int mUserId;
+ final IRemoteCallback mRemoteCallback;
+
+ LockNowCallback(int userId, IRemoteCallback remoteCallback) {
+ mUserId = userId;
+ mRemoteCallback = remoteCallback;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 2a1cb12c153e..f7ed10f40842 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -24,6 +24,7 @@ import android.annotation.SuppressLint
import android.os.Trace
import android.util.Log
import com.android.app.animation.Interpolators
+import com.android.app.tracing.coroutines.flow.traceAs
import com.android.app.tracing.coroutines.withContextTraced as withContext
import com.android.systemui.Flags.transitionRaceCondition
import com.android.systemui.dagger.SysUISingleton
@@ -43,7 +44,6 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
@@ -143,11 +143,12 @@ constructor(
@SuppressLint("SharedFlowCreation")
private val _transitions =
MutableSharedFlow<TransitionStep>(
- replay = 2,
- extraBufferCapacity = 20,
- onBufferOverflow = BufferOverflow.DROP_OLDEST,
- )
- override val transitions = _transitions.asSharedFlow().distinctUntilChanged()
+ replay = 2,
+ extraBufferCapacity = 20,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST,
+ )
+ .traceAs("KTR-transitions")
+ override val transitions = _transitions.distinctUntilChanged()
private var lastStep: TransitionStep = TransitionStep()
private var lastAnimator: ValueAnimator? = null
private var animatorListener: AnimatorListenerAdapter? = null
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt
index 80bdc65f9b97..f69229213690 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt
@@ -25,11 +25,17 @@ import kotlinx.coroutines.flow.MutableStateFlow
class LockscreenSceneTransitionRepository @Inject constructor() {
/**
- * This [KeyguardState] will indicate which sub state within KTF should be navigated to when the
- * next transition into the Lockscreen scene is started. It will be consumed exactly once and
- * after that the state will be set back to [DEFAULT_STATE].
+ * This [KeyguardState] will indicate which sub-state within KTF should be navigated to next.
+ *
+ * This can be either starting a transition to the `Lockscreen` scene or cancelling a transition
+ * from the `Lockscreen` scene and returning back to it.
+ *
+ * A `null` value means that no explicit target state was set and therefore the [DEFAULT_STATE]
+ * should be used.
+ *
+ * Once consumed, this state should be reset to `null`.
*/
- val nextLockscreenTargetState: MutableStateFlow<KeyguardState> = MutableStateFlow(DEFAULT_STATE)
+ val nextLockscreenTargetState: MutableStateFlow<KeyguardState?> = MutableStateFlow(null)
companion object {
val DEFAULT_STATE = KeyguardState.LOCKSCREEN
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index c755c4b02feb..a3796ab5ee27 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -17,8 +17,12 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
+import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -46,7 +50,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
-import com.android.app.tracing.coroutines.launchTraced as launch
@SysUISingleton
class FromAlternateBouncerTransitionInteractor
@@ -60,6 +63,8 @@ constructor(
@Main mainDispatcher: CoroutineDispatcher,
keyguardInteractor: KeyguardInteractor,
private val communalInteractor: CommunalInteractor,
+ private val communalSettingsInteractor: CommunalSettingsInteractor,
+ private val communalSceneInteractor: CommunalSceneInteractor,
powerInteractor: PowerInteractor,
keyguardOcclusionInteractor: KeyguardOcclusionInteractor,
private val primaryBouncerInteractor: PrimaryBouncerInteractor,
@@ -86,7 +91,7 @@ constructor(
.transition(
edge = Edge.create(from = KeyguardState.ALTERNATE_BOUNCER, to = Scenes.Gone),
edgeWithoutSceneContainer =
- Edge.create(from = KeyguardState.ALTERNATE_BOUNCER, to = KeyguardState.GONE)
+ Edge.create(from = KeyguardState.ALTERNATE_BOUNCER, to = KeyguardState.GONE),
)
.map {
// The alt bouncer is pretty fast to hide, so start the surface behind animation
@@ -112,27 +117,21 @@ constructor(
keyguardInteractor.primaryBouncerShowing,
powerInteractor.isAwake,
keyguardInteractor.isAodAvailable,
- communalInteractor.isIdleOnCommunal,
- communalInteractor.editModeOpen,
+ communalSceneInteractor.isIdleOnCommunal,
+ keyguardInteractor.isDreaming,
keyguardInteractor.isKeyguardOccluded,
)
.filterRelevantKeyguardStateAnd {
- (isAlternateBouncerShowing, isPrimaryBouncerShowing, _, _, _) ->
+ (isAlternateBouncerShowing, isPrimaryBouncerShowing, _, _, _, _) ->
!isAlternateBouncerShowing && !isPrimaryBouncerShowing
}
- .collect {
- (
- _,
- _,
- isAwake,
- isAodAvailable,
- isIdleOnCommunal,
- isCommunalEditMode,
- isOccluded) ->
+ .collect { (_, _, isAwake, isAodAvailable, isIdleOnCommunal, isDreaming, isOccluded)
+ ->
// When unlocking over glanceable hub to enter edit mode, transitioning directly
// to GONE prevents the lockscreen flash. Let listenForAlternateBouncerToGone
// handle it.
- if (isCommunalEditMode) return@collect
+ if (communalInteractor.editModeOpen.value) return@collect
+ val hubV2 = communalSettingsInteractor.isV2FlagEnabled()
val to =
if (!isAwake) {
if (isAodAvailable) {
@@ -141,16 +140,32 @@ constructor(
KeyguardState.DOZING
}
} else {
- if (isIdleOnCommunal) {
+ if (!hubV2 && isIdleOnCommunal) {
if (SceneContainerFlag.isEnabled) return@collect
KeyguardState.GLANCEABLE_HUB
- } else if (isOccluded) {
+ } else if (isOccluded && !isDreaming) {
KeyguardState.OCCLUDED
+ } else if (hubV2 && isDreaming) {
+ KeyguardState.DREAMING
+ } else if (hubV2 && isIdleOnCommunal) {
+ if (SceneContainerFlag.isEnabled) return@collect
+ KeyguardState.GLANCEABLE_HUB
} else {
KeyguardState.LOCKSCREEN
}
}
- startTransitionTo(to)
+
+ if (hubV2 && to != KeyguardState.GLANCEABLE_HUB && isIdleOnCommunal) {
+ // If bouncer is showing over the hub, we need to make sure we
+ // properly dismiss the hub when transitioning away.
+ communalSceneInteractor.changeScene(
+ newScene = CommunalScenes.Blank,
+ loggingReason = "alternate bouncer no longer showing over GH",
+ keyguardState = to,
+ )
+ } else {
+ startTransitionTo(to)
+ }
}
}
}
@@ -173,7 +188,7 @@ constructor(
} else {
emptyFlow()
}
- }
+ },
)
.filterRelevantKeyguardState()
.collect { startTransitionTo(KeyguardState.GONE) }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 30c1aac7b2a7..75d6631008ca 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -21,6 +21,7 @@ import android.util.Log
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
+import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -35,6 +36,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample
+import com.android.systemui.util.kotlin.sample
import com.android.wm.shell.shared.animation.Interpolators
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
@@ -42,6 +44,7 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
@@ -57,6 +60,7 @@ constructor(
@Main mainDispatcher: CoroutineDispatcher,
keyguardInteractor: KeyguardInteractor,
private val communalSceneInteractor: CommunalSceneInteractor,
+ private val communalSettingsInteractor: CommunalSettingsInteractor,
private val keyguardSecurityModel: KeyguardSecurityModel,
private val selectedUserInteractor: SelectedUserInteractor,
powerInteractor: PowerInteractor,
@@ -140,14 +144,17 @@ constructor(
)
.collect { (_, isAwake, isDreaming, isIdleOnCommunal) ->
val isOccluded = keyguardInteractor.isKeyguardOccluded.value
+ val hubV2 = communalSettingsInteractor.isV2FlagEnabled()
val toState =
if (isAwake) {
if (isOccluded && !isDreaming) {
KeyguardState.OCCLUDED
- } else if (isIdleOnCommunal) {
+ } else if (!hubV2 && isIdleOnCommunal) {
KeyguardState.GLANCEABLE_HUB
} else if (isDreaming) {
KeyguardState.DREAMING
+ } else if (hubV2 && isIdleOnCommunal) {
+ KeyguardState.GLANCEABLE_HUB
} else {
KeyguardState.LOCKSCREEN
}
@@ -161,7 +168,17 @@ constructor(
)
keyguardInteractor.asleepKeyguardState.value
}
- startTransitionTo(toState)
+ if (hubV2 && toState != KeyguardState.GLANCEABLE_HUB && isIdleOnCommunal) {
+ // If bouncer is showing over the hub, we need to make sure we
+ // properly dismiss the hub when transitioning away.
+ communalSceneInteractor.changeScene(
+ newScene = CommunalScenes.Blank,
+ loggingReason = "bouncer no longer showing over GH",
+ keyguardState = toState,
+ )
+ } else {
+ startTransitionTo(toState)
+ }
}
}
}
@@ -184,7 +201,32 @@ constructor(
private fun listenForPrimaryBouncerToAsleep() {
if (SceneContainerFlag.isEnabled) return
- scope.launch { listenForSleepTransition() }
+ scope.launch {
+ if (communalSettingsInteractor.isV2FlagEnabled()) {
+ powerInteractor.isAsleep
+ .filter { isAsleep -> isAsleep }
+ .filterRelevantKeyguardState()
+ .sample(communalSceneInteractor.isIdleOnCommunal)
+ .collect { isIdleOnCommunal ->
+ if (isIdleOnCommunal) {
+ // If the bouncer is showing on top of the hub, then ensure we also
+ // hide the hub.
+ communalSceneInteractor.changeScene(
+ newScene = CommunalScenes.Blank,
+ loggingReason = "Sleep while primary bouncer showing over hub",
+ keyguardState = keyguardInteractor.asleepKeyguardState.value,
+ )
+ } else {
+ startTransitionTo(
+ toState = keyguardInteractor.asleepKeyguardState.value,
+ ownerReason = "Sleep transition triggered",
+ )
+ }
+ }
+ } else {
+ listenForSleepTransition()
+ }
+ }
}
private fun listenForPrimaryBouncerToGone() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index 96e05cb7cd63..63cf4f72e415 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -24,7 +24,6 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardClockRepository
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.shared.model.ClockSizeSetting
-import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
@@ -33,10 +32,13 @@ import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarou
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockId
import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiAod
+import com.android.systemui.statusbar.notification.promoted.domain.interactor.AODPromotedNotificationInteractor
import com.android.systemui.util.kotlin.combine
+import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -45,6 +47,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -57,7 +60,8 @@ class KeyguardClockInteractor
constructor(
mediaCarouselInteractor: MediaCarouselInteractor,
activeNotificationsInteractor: ActiveNotificationsInteractor,
- shadeInteractor: ShadeInteractor,
+ aodPromotedNotificationInteractor: AODPromotedNotificationInteractor,
+ shadeModeInteractor: ShadeModeInteractor,
keyguardInteractor: KeyguardInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
headsUpNotificationInteractor: HeadsUpNotificationInteractor,
@@ -66,8 +70,13 @@ constructor(
private val wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor,
) {
private val isOnAod: Flow<Boolean> =
- keyguardTransitionInteractor.currentKeyguardState.map { it == KeyguardState.AOD }
+ keyguardTransitionInteractor.currentKeyguardState.map { it == AOD }
+ /**
+ * The clock size setting explicitly selected by the user. When it is `SMALL`, the large clock
+ * is never shown. When it is `DYNAMIC`, the clock size gets determined based on a combination
+ * of system signals.
+ */
val selectedClockSize: StateFlow<ClockSizeSetting> = keyguardClockRepository.selectedClockSize
val currentClockId: Flow<ClockId> = keyguardClockRepository.currentClockId
@@ -80,53 +89,91 @@ constructor(
var clock: ClockController? by keyguardClockRepository.clockEventController::clock
- val clockSize: StateFlow<ClockSize> =
+ private val isAodPromotedNotificationPresent: Flow<Boolean> =
+ if (PromotedNotificationUiAod.isEnabled) {
+ aodPromotedNotificationInteractor.isPresent
+ } else {
+ flowOf(false)
+ }
+
+ private val areAnyNotificationsPresent: Flow<Boolean> =
+ if (PromotedNotificationUiAod.isEnabled) {
+ combine(
+ activeNotificationsInteractor.areAnyNotificationsPresent,
+ isAodPromotedNotificationPresent,
+ ) { areAnyNotificationsPresent, isAodPromotedNotificationPresent ->
+ areAnyNotificationsPresent || isAodPromotedNotificationPresent
+ }
+ } else {
+ activeNotificationsInteractor.areAnyNotificationsPresent
+ }
+
+ private val dynamicClockSize: Flow<ClockSize> =
if (SceneContainerFlag.isEnabled) {
combine(
- shadeInteractor.isShadeLayoutWide,
- activeNotificationsInteractor.areAnyNotificationsPresent,
- mediaCarouselInteractor.hasActiveMediaOrRecommendation,
- keyguardInteractor.isDozing,
- isOnAod,
- ) { isShadeLayoutWide, hasNotifs, hasMedia, isDozing, isOnAod ->
- return@combine when {
- keyguardClockRepository.shouldForceSmallClock && !isOnAod -> ClockSize.SMALL
- !isShadeLayoutWide && (hasNotifs || hasMedia) -> ClockSize.SMALL
- !isShadeLayoutWide -> ClockSize.LARGE
- hasMedia && !isDozing -> ClockSize.SMALL
- else -> ClockSize.LARGE
- }
+ shadeModeInteractor.isShadeLayoutWide,
+ areAnyNotificationsPresent,
+ mediaCarouselInteractor.hasActiveMediaOrRecommendation,
+ keyguardInteractor.isDozing,
+ isOnAod,
+ ) { isShadeLayoutWide, hasNotifs, hasMedia, isDozing, isOnAod ->
+ when {
+ keyguardClockRepository.shouldForceSmallClock && !isOnAod -> ClockSize.SMALL
+ !isShadeLayoutWide && (hasNotifs || hasMedia) -> ClockSize.SMALL
+ !isShadeLayoutWide -> ClockSize.LARGE
+ hasMedia && !isDozing -> ClockSize.SMALL
+ else -> ClockSize.LARGE
}
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = ClockSize.LARGE,
- )
+ }
} else {
keyguardClockRepository.clockSize
}
+ val clockSize: StateFlow<ClockSize> =
+ selectedClockSize
+ .flatMapLatestConflated { selectedSize ->
+ if (selectedSize == ClockSizeSetting.SMALL) {
+ flowOf(ClockSize.SMALL)
+ } else {
+ dynamicClockSize
+ }
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = ClockSize.LARGE,
+ )
+
val clockShouldBeCentered: Flow<Boolean> =
if (SceneContainerFlag.isEnabled) {
combine(
- shadeInteractor.isShadeLayoutWide,
- activeNotificationsInteractor.areAnyNotificationsPresent,
+ shadeModeInteractor.isShadeLayoutWide,
+ areAnyNotificationsPresent,
+ isAodPromotedNotificationPresent,
isOnAod,
headsUpNotificationInteractor.isHeadsUpOrAnimatingAway,
keyguardInteractor.isDozing,
- ) { isShadeLayoutWide, areAnyNotificationsPresent, isOnAod, isHeadsUp, isDozing ->
+ ) {
+ isShadeLayoutWide,
+ areAnyNotificationsPresent,
+ isAodPromotedNotificationPresent,
+ isOnAod,
+ isHeadsUp,
+ isDozing ->
when {
!isShadeLayoutWide -> true
!areAnyNotificationsPresent -> true
// Pulsing notification appears on the right. Move clock left to avoid overlap.
isHeadsUp && isDozing -> false
+ isAodPromotedNotificationPresent -> false
else -> isOnAod
}
}
} else {
combine(
- shadeInteractor.isShadeLayoutWide,
- activeNotificationsInteractor.areAnyNotificationsPresent,
+ shadeModeInteractor.isShadeLayoutWide,
+ areAnyNotificationsPresent,
+ isAodPromotedNotificationPresent,
keyguardInteractor.dozeTransitionModel,
keyguardTransitionInteractor.startedKeyguardTransitionStep.map { it.to == AOD },
keyguardTransitionInteractor.startedKeyguardTransitionStep.map {
@@ -140,6 +187,7 @@ constructor(
) {
isShadeLayoutWide,
areAnyNotificationsPresent,
+ isAodPromotedNotificationPresent,
dozeTransitionModel,
startedToAod,
startedToLockScreen,
@@ -156,7 +204,7 @@ constructor(
// use null to skip emitting wrong value
startedToGone || startedToDoze -> null
startedToLockScreen -> !areAnyNotificationsPresent
- startedToAod -> !isPulsing
+ startedToAod -> !(isPulsing || isAodPromotedNotificationPresent)
else -> true
}
}
@@ -170,7 +218,7 @@ constructor(
val renderedClockId: ClockId
get() {
- return clock?.let { clock -> clock.config.id }
+ return clock?.config?.id
?: run {
Log.e(TAG, "No clock is available")
"MISSING_CLOCK_ID"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 58fb4230ccf5..3b4a1488095a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -19,7 +19,10 @@ package com.android.systemui.keyguard.domain.interactor
import android.annotation.SuppressLint
import android.util.Log
+import com.android.app.tracing.coroutines.flow.filterTraced
+import com.android.app.tracing.coroutines.flow.traceAs
import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.app.tracing.coroutines.traceCoroutine
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.Flags.keyguardTransitionForceFinishOnScreenOff
@@ -90,6 +93,7 @@ constructor(
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
.also { it.tryEmit(0f) }
+ .traceAs("KTF-${state.name}")
}
}
@@ -222,10 +226,11 @@ constructor(
val flow: Flow<TransitionStep> =
transitionMap.getOrPut(mappedEdge) {
- MutableSharedFlow(
- extraBufferCapacity = 10,
- onBufferOverflow = BufferOverflow.DROP_OLDEST,
- )
+ MutableSharedFlow<TransitionStep>(
+ extraBufferCapacity = 10,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST,
+ )
+ .traceAs("KTF-${mappedEdge.from}-to-${mappedEdge.to}")
}
if (!SceneContainerFlag.isEnabled) {
@@ -234,7 +239,7 @@ constructor(
if (edge.isSceneWildcardEdge()) {
return simulateTransitionStepsForSceneTransitions(edge)
}
- return flow.filter { step ->
+ return flow.filterTraced("stl-filter") { step ->
val fromScene =
when (edge) {
is Edge.StateToState -> edge.from?.mapToSceneContainerScene()
@@ -273,7 +278,7 @@ constructor(
step.transitionState == TransitionState.CANCELED) &&
sceneTransitionPair.value.previousValue.isTransitioning(fromScene, toScene)
- return@filter isTransitioningBetweenLockscreenStates ||
+ return@filterTraced isTransitioningBetweenLockscreenStates ||
isTransitioningBetweenDesiredScenes ||
terminalStepBelongsToPreviousTransition ||
belongsToInstantReversedTransition
@@ -362,27 +367,27 @@ constructor(
coroutineScope {
collect { value ->
- job?.cancelAndJoin()
+ traceCoroutine("cancelAndJoin") { job?.cancelAndJoin() }
- job = launch {
+ job = launch("inner") {
val innerFlow = transform(value)
try {
innerFlow.collect { step ->
if (step.transitionState == TransitionState.STARTED) {
startedEmitted = true
}
- send(step)
+ traceCoroutine("send($step)") { send(step) }
}
} finally {
if (startedEmitted) {
- send(
+ val step =
TransitionStep(
from = UNDEFINED,
to = UNDEFINED,
value = 1f,
transitionState = TransitionState.FINISHED,
)
- )
+ traceCoroutine("send($step)") { send(step) }
startedEmitted = false
}
}
@@ -390,6 +395,7 @@ constructor(
}
}
}
+ .traceAs("flatMapLatestWithFinished")
/**
* Converts old KTF states to UNDEFINED when [SceneContainerFlag] is enabled.
@@ -545,6 +551,7 @@ constructor(
}
}
.onStart { emit(false) }
+ .traceAs("isInTransition-$edge-$edgeWithoutSceneContainer")
.distinctUntilChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
index 5f821022d580..1b70ff84f09d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
@@ -119,7 +119,8 @@ constructor(
} else {
val targetState =
if (idle.currentScene == Scenes.Lockscreen) {
- transitionInteractor.startedKeyguardTransitionStep.value.from
+ repository.nextLockscreenTargetState.value
+ ?: transitionInteractor.startedKeyguardTransitionStep.value.from
} else {
UNDEFINED
}
@@ -197,11 +198,11 @@ constructor(
TransitionInfo(
ownerName = this::class.java.simpleName,
from = UNDEFINED,
- to = repository.nextLockscreenTargetState.value,
+ to = repository.nextLockscreenTargetState.value ?: DEFAULT_STATE,
animator = null,
modeOnCanceled = TransitionModeOnCanceled.RESET,
)
- repository.nextLockscreenTargetState.value = DEFAULT_STATE
+ repository.nextLockscreenTargetState.value = null
startTransition(newTransition)
}
@@ -215,7 +216,7 @@ constructor(
animator = null,
modeOnCanceled = TransitionModeOnCanceled.RESET,
)
- repository.nextLockscreenTargetState.value = DEFAULT_STATE
+ repository.nextLockscreenTargetState.value = null
startTransition(newTransition)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 00710c97d00a..da87e38daa9b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -300,7 +300,7 @@ object KeyguardRootViewBinder {
}
launch {
- viewModel.isNotifIconContainerVisible.collect { isVisible ->
+ viewModel.isAodPromotedNotifVisible.collect { isVisible ->
if (isVisible.value) {
blueprintViewModel.refreshBlueprint()
}
@@ -370,6 +370,14 @@ object KeyguardRootViewBinder {
repeatOnLifecycle(Lifecycle.State.STARTED) {
if (wallpaperFocalAreaViewModel.hasFocalArea.value) {
launch {
+ wallpaperFocalAreaViewModel.wallpaperFocalAreaBounds.collect {
+ wallpaperFocalAreaBounds ->
+ wallpaperFocalAreaViewModel.setFocalAreaBounds(
+ wallpaperFocalAreaBounds
+ )
+ }
+ }
+ launch {
wallpaperFocalAreaViewModel.wallpaperFocalAreaBounds
.filterNotNull()
.collect { wallpaperFocalAreaViewModel.setFocalAreaBounds(it) }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
index 97fa3f19a82e..f0113a5b6020 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
@@ -26,7 +26,6 @@ import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.shared.Flags.ambientAod
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.wallpapers.ui.viewmodel.WallpaperViewModel
-import com.android.app.tracing.coroutines.launchTraced as launch
object LightRevealScrimViewBinder {
@JvmStatic
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index aed86648e3cf..0a087404c075 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -26,7 +26,6 @@ import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.BurnInModel
-import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.StateToValue
@@ -35,6 +34,7 @@ import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject
import kotlin.math.max
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -51,6 +51,7 @@ import kotlinx.coroutines.flow.stateIn
* Models UI state for elements that need to apply anti-burn-in tactics when showing in AOD
* (always-on display).
*/
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class AodBurnInViewModel
@Inject
@@ -184,10 +185,9 @@ constructor(
keyguardClockViewModel.currentClock.value
?.config
?.useAlternateSmartspaceAODTransition == true
- // Only scale large non-weather clocks
- // elements in large weather clock will translate the same as smartspace
- val useScaleOnly =
- (!useAltAod) && keyguardClockViewModel.clockSize.value == ClockSize.LARGE
+ // Only scale large non-weather clocks elements in large weather clock will translate
+ // the same as smartspace
+ val useScaleOnly = (!useAltAod) && keyguardClockViewModel.isLargeClockVisible.value
val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolated).toInt()
val translationY = max(params.topInset - params.minViewY, burnInY)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index 88fdc83fa7a0..cf5cc264be8d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.content.Context
import android.content.res.Resources
-import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.helper.widget.Layer
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.customization.R as customR
@@ -27,11 +26,10 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.shared.model.ClockSize
-import com.android.systemui.keyguard.shared.model.ClockSizeSetting
import com.android.systemui.plugins.clocks.ClockPreviewConfig
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.ShadeDisplayAware
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
import javax.inject.Inject
@@ -47,11 +45,11 @@ import kotlinx.coroutines.flow.stateIn
class KeyguardClockViewModel
@Inject
constructor(
- val context: Context,
+ private val context: Context,
keyguardClockInteractor: KeyguardClockInteractor,
@Application private val applicationScope: CoroutineScope,
aodNotificationIconViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
- @get:VisibleForTesting val shadeInteractor: ShadeInteractor,
+ private val shadeModeInteractor: ShadeModeInteractor,
private val systemBarUtils: SystemBarUtilsProxy,
@ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
// TODO: b/374267505 - Use ShadeDisplayAware resources here.
@@ -59,17 +57,7 @@ constructor(
) {
var burnInLayer: Layer? = null
- val clockSize: StateFlow<ClockSize> =
- combine(keyguardClockInteractor.selectedClockSize, keyguardClockInteractor.clockSize) {
- selectedSize,
- clockSize ->
- if (selectedSize == ClockSizeSetting.SMALL) ClockSize.SMALL else clockSize
- }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = ClockSize.LARGE,
- )
+ val clockSize: StateFlow<ClockSize> = keyguardClockInteractor.clockSize
val isLargeClockVisible: StateFlow<Boolean> =
clockSize
@@ -118,7 +106,7 @@ constructor(
combine(
isLargeClockVisible,
clockShouldBeCentered,
- shadeInteractor.isShadeLayoutWide,
+ shadeModeInteractor.isShadeLayoutWide,
currentClock,
) { isLargeClockVisible, clockShouldBeCentered, isShadeLayoutWide, currentClock ->
if (currentClock?.config?.useCustomClockScene == true) {
@@ -163,7 +151,7 @@ constructor(
fun getSmallClockTopMargin(): Int {
return ClockPreviewConfig(
context,
- shadeInteractor.isShadeLayoutWide.value,
+ shadeModeInteractor.isShadeLayoutWide.value,
SceneContainerFlag.isEnabled,
)
.getSmallClockTopPadding(systemBarUtils.getStatusBarHeaderHeightKeyguard())
@@ -172,7 +160,7 @@ constructor(
val smallClockTopMargin =
combine(
configurationInteractor.onAnyConfigurationChange,
- shadeInteractor.isShadeLayoutWide,
+ shadeModeInteractor.isShadeLayoutWide,
) { _, _ ->
getSmallClockTopMargin()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt
index ba03c48c65e9..e70d696a207f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt
@@ -21,6 +21,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -31,6 +32,7 @@ class KeyguardMediaViewModel
constructor(
mediaCarouselInteractor: MediaCarouselInteractor,
keyguardInteractor: KeyguardInteractor,
+ shadeModeInteractor: ShadeModeInteractor,
) : ExclusiveActivatable() {
private val hydrator = Hydrator("KeyguardMediaViewModel.hydrator")
@@ -54,6 +56,12 @@ constructor(
mediaCarouselInteractor.hasActiveMediaOrRecommendation.value,
)
+ val isShadeLayoutWide: Boolean by
+ hydrator.hydratedStateOf(
+ traceName = "isShadeLayoutWide",
+ source = shadeModeInteractor.isShadeLayoutWide,
+ )
+
override suspend fun onActivated(): Nothing {
hydrator.activate()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 62a5ebab29e0..8e21745e1a31 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -25,6 +25,7 @@ import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.PulseExpansionInteractor
@@ -44,9 +45,11 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.ui.viewmodel.NotificationShadeWindowModel
import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
+import com.android.systemui.statusbar.notification.promoted.domain.interactor.AODPromotedNotificationInteractor
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
+import com.android.systemui.util.kotlin.FlowDumperImpl
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.ui.AnimatableEvent
@@ -82,6 +85,7 @@ constructor(
private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
private val pulseExpansionInteractor: PulseExpansionInteractor,
notificationShadeWindowModel: NotificationShadeWindowModel,
+ private val aodPromotedNotificationInteractor: AODPromotedNotificationInteractor,
private val aodNotificationIconViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
private val alternateBouncerToAodTransitionViewModel: AlternateBouncerToAodTransitionViewModel,
private val alternateBouncerToGoneTransitionViewModel:
@@ -134,17 +138,21 @@ constructor(
private val aodBurnInViewModel: AodBurnInViewModel,
private val shadeInteractor: ShadeInteractor,
wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor,
-) {
+ dumpManager: DumpManager,
+) : FlowDumperImpl(dumpManager) {
val burnInLayerVisibility: Flow<Int> =
keyguardTransitionInteractor.startedKeyguardTransitionStep
.filter { it.to == AOD || it.to == LOCKSCREEN }
.map { VISIBLE }
+ .dumpWhileCollecting("burnInLayerVisibility")
val goneToAodTransition =
- keyguardTransitionInteractor.transition(
- edge = Edge.create(Scenes.Gone, AOD),
- edgeWithoutSceneContainer = Edge.create(GONE, AOD),
- )
+ keyguardTransitionInteractor
+ .transition(
+ edge = Edge.create(Scenes.Gone, AOD),
+ edgeWithoutSceneContainer = Edge.create(GONE, AOD),
+ )
+ .dumpWhileCollecting("goneToAodTransition")
private val goneToAodTransitionRunning: Flow<Boolean> =
goneToAodTransition
@@ -222,13 +230,15 @@ constructor(
)
/** Last point that the root view was tapped */
- val lastRootViewTapPosition: Flow<Point?> = keyguardInteractor.lastRootViewTapPosition
+ val lastRootViewTapPosition: Flow<Point?> =
+ keyguardInteractor.lastRootViewTapPosition.dumpWhileCollecting("lastRootViewTapPosition")
/**
* The keyguard root view can be clipped as the shade is pulled down, typically only for
* non-split shade cases.
*/
- val topClippingBounds: Flow<Int?> = keyguardInteractor.topClippingBounds
+ val topClippingBounds: Flow<Int?> =
+ keyguardInteractor.topClippingBounds.dumpWhileCollecting("topClippingBounds")
/** An observable for the alpha level for the entire keyguard root view. */
fun alpha(viewState: ViewStateAccessor): Flow<Float> {
@@ -287,40 +297,56 @@ constructor(
}
}
.distinctUntilChanged()
+ .dumpWhileCollecting("alpha")
}
val scaleFromZoomOut: Flow<Float> =
- keyguardInteractor.zoomOut.map { 1 - it * PUSHBACK_SCALE_FOR_LOCKSCREEN }
+ keyguardInteractor.zoomOut
+ .map { 1 - it * PUSHBACK_SCALE_FOR_LOCKSCREEN }
+ .dumpWhileCollecting("scaleFromZoomOut")
- val translationY: Flow<Float> = aodBurnInViewModel.movement.map { it.translationY.toFloat() }
+ val translationY: Flow<Float> =
+ aodBurnInViewModel.movement
+ .map { it.translationY.toFloat() }
+ .dumpWhileCollecting("translationY")
val translationX: Flow<StateToValue> =
merge(
- aodBurnInViewModel.movement.map {
- StateToValue(to = AOD, value = it.translationX.toFloat())
- },
- lockscreenToGlanceableHubTransitionViewModel.keyguardTranslationX,
- glanceableHubToLockscreenTransitionViewModel.keyguardTranslationX,
- )
+ aodBurnInViewModel.movement.map {
+ StateToValue(to = AOD, value = it.translationX.toFloat())
+ },
+ lockscreenToGlanceableHubTransitionViewModel.keyguardTranslationX,
+ glanceableHubToLockscreenTransitionViewModel.keyguardTranslationX,
+ )
+ .dumpWhileCollecting("translationX")
fun updateBurnInParams(params: BurnInParameters) {
aodBurnInViewModel.updateBurnInParams(params)
}
val scale: Flow<BurnInScaleViewModel> =
- aodBurnInViewModel.movement.map {
- BurnInScaleViewModel(scale = it.scale, scaleClockOnly = it.scaleClockOnly)
- }
+ aodBurnInViewModel.movement
+ .map { BurnInScaleViewModel(scale = it.scale, scaleClockOnly = it.scaleClockOnly) }
+ .dumpWhileCollecting("scale")
- val isAodPromotedNotifVisible: StateFlow<Boolean> =
- keyguardTransitionInteractor
- .transitionValue(AOD)
- .map { it == 1f }
+ val isAodPromotedNotifVisible: StateFlow<AnimatedValue<Boolean>> =
+ combine(
+ areNotifsFullyHiddenAnimated(),
+ isPulseExpandingAnimated(),
+ aodPromotedNotificationInteractor.isPresent,
+ ) { notifsFullyHiddenAnimated, pulseExpandingAnimated, haveAodPromotedNotif ->
+ zip(notifsFullyHiddenAnimated, pulseExpandingAnimated) {
+ notifsFullyHidden,
+ pulseExpanding ->
+ notifsFullyHidden && !pulseExpanding && haveAodPromotedNotif
+ }
+ }
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = false,
+ initialValue = AnimatedValue.NotAnimating(false),
)
+ .dumpValue("isAodPromotedNotifVisible")
/** Is the notification icon container visible? */
val isNotifIconContainerVisible: StateFlow<AnimatedValue<Boolean>> =
@@ -376,6 +402,7 @@ constructor(
started = SharingStarted.WhileSubscribed(),
initialValue = AnimatedValue.NotAnimating(false),
)
+ .dumpValue("isNotifIconContainerVisible")
fun onNotificationContainerBoundsChanged(top: Float, bottom: Float, animate: Boolean = false) {
keyguardInteractor.setNotificationContainerBounds(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index 3e3a89a55f66..ecebaee62862 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -17,8 +17,9 @@
package com.android.systemui.keyguard.ui.viewmodel
import android.content.res.Resources
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
import com.android.app.tracing.coroutines.launchTraced as launch
-import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.biometrics.AuthController
import com.android.systemui.customization.R as customR
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
@@ -30,86 +31,121 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.transition.KeyguardTransitionAnimationCallback
import com.android.systemui.keyguard.shared.transition.KeyguardTransitionAnimationCallbackDelegator
import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.res.R
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
class LockscreenContentViewModel
@AssistedInject
constructor(
- clockInteractor: KeyguardClockInteractor,
- private val interactor: KeyguardBlueprintInteractor,
+ private val clockInteractor: KeyguardClockInteractor,
+ interactor: KeyguardBlueprintInteractor,
private val authController: AuthController,
val touchHandling: KeyguardTouchHandlingViewModel,
- private val shadeInteractor: ShadeInteractor,
- private val unfoldTransitionInteractor: UnfoldTransitionInteractor,
- private val deviceEntryInteractor: DeviceEntryInteractor,
- private val transitionInteractor: KeyguardTransitionInteractor,
+ shadeModeInteractor: ShadeModeInteractor,
+ unfoldTransitionInteractor: UnfoldTransitionInteractor,
+ deviceEntryInteractor: DeviceEntryInteractor,
+ transitionInteractor: KeyguardTransitionInteractor,
private val keyguardTransitionAnimationCallbackDelegator:
KeyguardTransitionAnimationCallbackDelegator,
@Assisted private val keyguardTransitionAnimationCallback: KeyguardTransitionAnimationCallback,
) : ExclusiveActivatable() {
- @VisibleForTesting val clockSize = clockInteractor.clockSize
+
+ private val hydrator = Hydrator("LockscreenContentViewModel.hydrator")
val isUdfpsVisible: Boolean
get() = authController.isUdfpsSupported
- val isShadeLayoutWide: StateFlow<Boolean> = shadeInteractor.isShadeLayoutWide
+ /** Where to place the notifications stack on the lockscreen. */
+ val notificationsPlacement: NotificationsPlacement by
+ hydrator.hydratedStateOf(
+ traceName = "notificationsPlacement",
+ initialValue = NotificationsPlacement.BelowClock,
+ source =
+ combine(shadeModeInteractor.shadeMode, clockInteractor.clockSize) {
+ shadeMode,
+ clockSize ->
+ if (shadeMode is ShadeMode.Split) {
+ NotificationsPlacement.BesideClock(alignment = Alignment.TopEnd)
+ } else if (clockSize == ClockSize.SMALL) {
+ NotificationsPlacement.BelowClock
+ } else {
+ NotificationsPlacement.BesideClock(alignment = Alignment.TopStart)
+ }
+ },
+ )
- private val _unfoldTranslations = MutableStateFlow(UnfoldTranslations())
/** Amount of horizontal translation that should be applied to elements in the scene. */
- val unfoldTranslations: StateFlow<UnfoldTranslations> = _unfoldTranslations.asStateFlow()
+ val unfoldTranslations: UnfoldTranslations by
+ hydrator.hydratedStateOf(
+ traceName = "unfoldTranslations",
+ initialValue = UnfoldTranslations(),
+ source =
+ combine(
+ unfoldTransitionInteractor.unfoldTranslationX(isOnStartSide = true),
+ unfoldTransitionInteractor.unfoldTranslationX(isOnStartSide = false),
+ ::UnfoldTranslations,
+ ),
+ )
- private val _isContentVisible = MutableStateFlow(true)
/** Whether the content of the scene UI should be shown. */
- val isContentVisible: StateFlow<Boolean> = _isContentVisible.asStateFlow()
+ val isContentVisible: Boolean by
+ hydrator.hydratedStateOf(
+ traceName = "isContentVisible",
+ initialValue = true,
+ // Content is visible unless we're OCCLUDED. Currently, we don't have nice animations
+ // into and out of OCCLUDED, so the lockscreen/AOD content is hidden immediately upon
+ // entering/exiting OCCLUDED.
+ source = transitionInteractor.transitionValue(KeyguardState.OCCLUDED).map { it == 0f },
+ )
+
+ /** Indicates whether lockscreen notifications should be rendered. */
+ val areNotificationsVisible: Boolean by
+ hydrator.hydratedStateOf(
+ traceName = "areNotificationsVisible",
+ initialValue = false,
+ // Content is visible unless we're OCCLUDED. Currently, we don't have nice animations
+ // into and out of OCCLUDED, so the lockscreen/AOD content is hidden immediately upon
+ // entering/exiting OCCLUDED.
+ source =
+ combine(clockInteractor.clockSize, shadeModeInteractor.isShadeLayoutWide) {
+ clockSize,
+ isShadeLayoutWide ->
+ clockSize == ClockSize.SMALL || isShadeLayoutWide
+ },
+ )
/** @see DeviceEntryInteractor.isBypassEnabled */
- val isBypassEnabled: StateFlow<Boolean>
- get() = deviceEntryInteractor.isBypassEnabled
+ val isBypassEnabled: Boolean by
+ hydrator.hydratedStateOf(
+ traceName = "isBypassEnabled",
+ source = deviceEntryInteractor.isBypassEnabled,
+ )
+
+ val blueprintId: String by
+ hydrator.hydratedStateOf(
+ traceName = "blueprintId",
+ initialValue = interactor.getCurrentBlueprint().id,
+ source = interactor.blueprint.map { it.id }.distinctUntilChanged(),
+ )
override suspend fun onActivated(): Nothing {
coroutineScope {
try {
+ launch { hydrator.activate() }
+
keyguardTransitionAnimationCallbackDelegator.delegate =
keyguardTransitionAnimationCallback
- launch {
- combine(
- unfoldTransitionInteractor.unfoldTranslationX(isOnStartSide = true),
- unfoldTransitionInteractor.unfoldTranslationX(isOnStartSide = false),
- ) { start, end ->
- UnfoldTranslations(start = start, end = end)
- }
- .collect { _unfoldTranslations.value = it }
- }
-
- launch {
- transitionInteractor
- .transitionValue(KeyguardState.OCCLUDED)
- .map { it > 0f }
- .collect { fullyOrPartiallyOccluded ->
- // Content is visible unless we're OCCLUDED. Currently, we don't have
- // nice
- // animations into and out of OCCLUDED, so the lockscreen/AOD content is
- // hidden immediately upon entering/exiting OCCLUDED.
- _isContentVisible.value = !fullyOrPartiallyOccluded
- }
- }
awaitCancellation()
} finally {
@@ -118,16 +154,8 @@ constructor(
}
}
- /** Returns a flow that indicates whether lockscreen notifications should be rendered. */
- fun areNotificationsVisible(): Flow<Boolean> {
- return combine(clockSize, shadeInteractor.isShadeLayoutWide) { clockSize, isShadeLayoutWide
- ->
- clockSize == ClockSize.SMALL || isShadeLayoutWide
- }
- }
-
fun getSmartSpacePaddingTop(resources: Resources): Int {
- return if (clockSize.value == ClockSize.LARGE) {
+ return if (clockInteractor.clockSize.value == ClockSize.LARGE) {
resources.getDimensionPixelSize(customR.dimen.keyguard_smartspace_top_offset) +
resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin)
} else {
@@ -135,17 +163,6 @@ constructor(
}
}
- fun blueprintId(scope: CoroutineScope): StateFlow<String> {
- return interactor.blueprint
- .map { it.id }
- .distinctUntilChanged()
- .stateIn(
- scope = scope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = interactor.getCurrentBlueprint().id,
- )
- }
-
data class UnfoldTranslations(
/**
@@ -162,6 +179,15 @@ constructor(
val end: Float = 0f,
)
+ /** Where to place the notifications stack on the lockscreen. */
+ sealed interface NotificationsPlacement {
+ /** Show notifications below the lockscreen clock. */
+ data object BelowClock : NotificationsPlacement
+
+ /** Show notifications side-by-side with the clock. */
+ data class BesideClock(val alignment: Alignment) : NotificationsPlacement
+ }
+
@AssistedFactory
interface Factory {
fun create(
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt
index c3182bf7a320..1466d8b4288e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt
@@ -143,6 +143,12 @@ interface MediaDataManager {
* place immediately.
*/
override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {}
+
+ /**
+ * Called whenever the current active media notification changes. Should only be used if
+ * [SceneContainerFlag] is disabled
+ */
+ override fun onCurrentActiveMediaChanged(key: String?, data: MediaData?) {}
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
index 1464849156dc..59f98d83e149 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
@@ -1434,6 +1434,9 @@ class MediaDataProcessor(
* place immediately.
*/
fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean = true) {}
+
+ /** Called whenever the current active media notification changes */
+ fun onCurrentActiveMediaChanged(key: String?, data: MediaData?) {}
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index 173b600de06b..93c4bafe4273 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -87,6 +87,7 @@ import com.android.systemui.shared.system.SysUiStatsLog.SMART_SPACE_CARD_REPORTE
import com.android.systemui.shared.system.SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY as SSPACE_CARD_REPORTED__DREAM_OVERLAY
import com.android.systemui.shared.system.SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN as SSPACE_CARD_REPORTED__LOCKSCREEN
import com.android.systemui.shared.system.SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE
+import com.android.systemui.statusbar.featurepods.media.domain.interactor.MediaControlChipInteractor
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -155,6 +156,7 @@ constructor(
private val mediaCarouselViewModel: MediaCarouselViewModel,
private val mediaViewControllerFactory: Provider<MediaViewController>,
private val deviceEntryInteractor: DeviceEntryInteractor,
+ private val mediaControlChipInteractor: MediaControlChipInteractor,
) : Dumpable {
/** The current width of the carousel */
var currentCarouselWidth: Int = 0
@@ -957,6 +959,9 @@ constructor(
}
}
mediaCarouselScrollHandler.onPlayersChanged()
+ mediaControlChipInteractor.updateMediaControlChipModelLegacy(
+ MediaPlayerData.getFirstActiveMediaData()
+ )
MediaPlayerData.updateVisibleMediaPlayers()
// Automatically scroll to the active player if needed
if (shouldScrollToKey) {
@@ -1015,6 +1020,9 @@ constructor(
)
updatePageIndicator()
mediaCarouselScrollHandler.onPlayersChanged()
+ mediaControlChipInteractor.updateMediaControlChipModelLegacy(
+ MediaPlayerData.getFirstActiveMediaData()
+ )
mediaFrame.requiresRemeasuring = true
onUiExecutionEnd?.run()
}
@@ -1023,6 +1031,9 @@ constructor(
updatePlayer(key, data, isSsReactivated, curVisibleMediaKey, existingPlayer)
updatePageIndicator()
mediaCarouselScrollHandler.onPlayersChanged()
+ mediaControlChipInteractor.updateMediaControlChipModelLegacy(
+ MediaPlayerData.getFirstActiveMediaData()
+ )
mediaFrame.requiresRemeasuring = true
onUiExecutionEnd?.run()
}
@@ -1036,6 +1047,9 @@ constructor(
}
updatePageIndicator()
mediaCarouselScrollHandler.onPlayersChanged()
+ mediaControlChipInteractor.updateMediaControlChipModelLegacy(
+ MediaPlayerData.getFirstActiveMediaData()
+ )
mediaFrame.requiresRemeasuring = true
onUiExecutionEnd?.run()
}
@@ -1194,6 +1208,9 @@ constructor(
mediaContent.removeView(removed.recommendationViewHolder?.recommendations)
removed.onDestroy()
mediaCarouselScrollHandler.onPlayersChanged()
+ mediaControlChipInteractor.updateMediaControlChipModelLegacy(
+ MediaPlayerData.getFirstActiveMediaData()
+ )
updatePageIndicator()
if (dismissMediaData) {
@@ -1928,6 +1945,16 @@ internal object MediaPlayerData {
fun visiblePlayerKeys() = visibleMediaPlayers.values
+ /** Returns the [MediaData] associated with the first mediaPlayer in the mediaCarousel. */
+ fun getFirstActiveMediaData(): MediaData? {
+ mediaPlayers.entries.forEach { entry ->
+ if (!entry.key.isSsMediaRec && entry.key.data.active) {
+ return entry.key.data
+ }
+ }
+ return null
+ }
+
/** Returns the index of the first non-timeout media. */
fun firstActiveMediaIndex(): Int {
mediaPlayers.entries.forEachIndexed { index, e ->
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
index c1778119a3fd..2b36872dbe36 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
@@ -1040,13 +1040,19 @@ constructor(
expandedLayout.load(context, R.xml.media_recommendations_expanded)
}
}
- readjustPlayPauseWidth()
+ readjustUIUpdateConstraints()
refreshState()
}
- private fun readjustPlayPauseWidth() {
+ private fun readjustUIUpdateConstraints() {
// TODO: move to xml file when flag is removed.
if (Flags.mediaControlsUiUpdate()) {
+ collapsedLayout.setGuidelineEnd(
+ R.id.action_button_guideline,
+ context.resources.getDimensionPixelSize(
+ R.dimen.qs_media_session_collapsed_guideline
+ ),
+ )
collapsedLayout.constrainWidth(
R.id.actionPlayPause,
context.resources.getDimensionPixelSize(R.dimen.qs_media_action_play_pause_width),
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelListUpdateCallback.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelListUpdateCallback.kt
index 709723fa9480..6022b7b1fc13 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelListUpdateCallback.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelListUpdateCallback.kt
@@ -18,6 +18,7 @@ package com.android.systemui.media.controls.ui.util
import androidx.recyclerview.widget.ListUpdateCallback
import com.android.systemui.media.controls.ui.viewmodel.MediaCommonViewModel
+import kotlin.math.min
/** A [ListUpdateCallback] to apply media events needed to reach the new state. */
class MediaViewModelListUpdateCallback(
@@ -46,7 +47,7 @@ class MediaViewModelListUpdateCallback(
}
override fun onChanged(position: Int, count: Int, payload: Any?) {
- for (i in position until position + count) {
+ for (i in position until min(position + count, new.size)) {
onUpdated(new[i], position)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
deleted file mode 100644
index 3d2aafeba1a5..000000000000
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.dialog;
-
-import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_GO_TO_APP;
-import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_NONE;
-import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
-
-import android.annotation.DrawableRes;
-import android.annotation.StringRes;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CheckBox;
-import android.widget.TextView;
-
-import androidx.annotation.DoNotInline;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.core.widget.CompoundButtonCompat;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.media.flags.Flags;
-import com.android.settingslib.media.LocalMediaManager.MediaDeviceState;
-import com.android.settingslib.media.MediaDevice;
-import com.android.systemui.res.R;
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Adapter for media output dialog.
- */
-public class MediaOutputAdapter extends MediaOutputBaseAdapter {
-
- private static final String TAG = "MediaOutputAdapter";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final float DEVICE_DISABLED_ALPHA = 0.5f;
- private static final float DEVICE_ACTIVE_ALPHA = 1f;
- protected List<MediaItem> mMediaItemList = new CopyOnWriteArrayList<>();
- private boolean mShouldGroupSelectedMediaItems = Flags.enableOutputSwitcherDeviceGrouping();
-
- public MediaOutputAdapter(MediaSwitchingController controller) {
- super(controller);
- setHasStableIds(true);
- }
-
- @Override
- public void updateItems() {
- mMediaItemList.clear();
- mMediaItemList.addAll(mController.getMediaItemList());
- if (mShouldGroupSelectedMediaItems) {
- if (mController.getSelectedMediaDevice().size() == 1) {
- // Don't group devices if initially there isn't more than one selected.
- mShouldGroupSelectedMediaItems = false;
- }
- }
- notifyDataSetChanged();
- }
-
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
- int viewType) {
- super.onCreateViewHolder(viewGroup, viewType);
- switch (viewType) {
- case MediaItem.MediaItemType.TYPE_GROUP_DIVIDER:
- return new MediaGroupDividerViewHolder(mHolderView);
- case MediaItem.MediaItemType.TYPE_PAIR_NEW_DEVICE:
- case MediaItem.MediaItemType.TYPE_DEVICE:
- default:
- return new MediaDeviceViewHolder(mHolderView);
- }
- }
-
- @Override
- public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
- if (position >= mMediaItemList.size()) {
- if (DEBUG) {
- Log.d(TAG, "Incorrect position: " + position + " list size: "
- + mMediaItemList.size());
- }
- return;
- }
- MediaItem currentMediaItem = mMediaItemList.get(position);
- switch (currentMediaItem.getMediaItemType()) {
- case MediaItem.MediaItemType.TYPE_GROUP_DIVIDER:
- ((MediaGroupDividerViewHolder) viewHolder).onBind(currentMediaItem.getTitle());
- break;
- case MediaItem.MediaItemType.TYPE_PAIR_NEW_DEVICE:
- ((MediaDeviceViewHolder) viewHolder).onBindPairNewDevice();
- break;
- case MediaItem.MediaItemType.TYPE_DEVICE:
- ((MediaDeviceViewHolder) viewHolder).onBind(
- currentMediaItem,
- position);
- break;
- default:
- Log.d(TAG, "Incorrect position: " + position);
- }
- }
-
- @Override
- public long getItemId(int position) {
- if (position >= mMediaItemList.size()) {
- Log.d(TAG, "Incorrect position for item id: " + position);
- return position;
- }
- MediaItem currentMediaItem = mMediaItemList.get(position);
- return currentMediaItem.getMediaDevice().isPresent()
- ? currentMediaItem.getMediaDevice().get().getId().hashCode()
- : position;
- }
-
- @Override
- public int getItemViewType(int position) {
- if (position >= mMediaItemList.size()) {
- Log.d(TAG, "Incorrect position for item type: " + position);
- return MediaItem.MediaItemType.TYPE_GROUP_DIVIDER;
- }
- return mMediaItemList.get(position).getMediaItemType();
- }
-
- @Override
- public int getItemCount() {
- return mMediaItemList.size();
- }
-
- class MediaDeviceViewHolder extends MediaDeviceBaseViewHolder {
-
- MediaDeviceViewHolder(View view) {
- super(view);
- }
-
- void onBind(MediaItem mediaItem, int position) {
- MediaDevice device = mediaItem.getMediaDevice().get();
- super.onBind(device, position);
- boolean isMutingExpectedDeviceExist = mController.hasMutingExpectedDevice();
- final boolean currentlyConnected = isCurrentlyConnected(device);
- boolean isSelected = isDeviceIncluded(mController.getSelectedMediaDevice(), device);
- boolean isDeselectable =
- isDeviceIncluded(mController.getDeselectableMediaDevice(), device);
- boolean isSelectable = isDeviceIncluded(mController.getSelectableMediaDevice(), device);
- boolean isTransferable =
- isDeviceIncluded(mController.getTransferableMediaDevices(), device);
- boolean hasRouteListingPreferenceItem = device.hasRouteListingPreferenceItem();
-
- if (DEBUG) {
- Log.d(
- TAG,
- "["
- + position
- + "] "
- + device.getName()
- + " ["
- + (isDeselectable ? "deselectable" : "")
- + "] ["
- + (isSelected ? "selected" : "")
- + "] ["
- + (isSelectable ? "selectable" : "")
- + "] ["
- + (isTransferable ? "transferable" : "")
- + "] ["
- + (hasRouteListingPreferenceItem ? "hasListingPreference" : "")
- + "]");
- }
-
- boolean isDeviceGroup = false;
- GroupStatus groupStatus = null;
- OngoingSessionStatus ongoingSessionStatus = null;
- ConnectionState connectionState = ConnectionState.DISCONNECTED;
- boolean restrictVolumeAdjustment = mController.hasAdjustVolumeUserRestriction();
- String subtitle = null;
- Drawable deviceStatusIcon = null;
- boolean deviceDisabled = false;
- View.OnClickListener clickListener = null;
-
- if (mCurrentActivePosition == position) {
- mCurrentActivePosition = -1;
- }
- mItemLayout.setVisibility(View.VISIBLE);
-
- if (mController.isAnyDeviceTransferring()) {
- if (device.getState() == MediaDeviceState.STATE_CONNECTING) {
- connectionState = ConnectionState.CONNECTING;
- }
- } else {
- // Set different layout for each device
- if (device.isMutingExpectedDevice()
- && !mController.isCurrentConnectedDeviceRemote()) {
- connectionState = ConnectionState.CONNECTED;
- restrictVolumeAdjustment = true;
- mCurrentActivePosition = position;
- clickListener = v -> onItemClick(v, device);
- } else if (mShouldGroupSelectedMediaItems
- && mController.getSelectedMediaDevice().size() > 1
- && isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
- if (!mediaItem.isFirstDeviceInGroup()) {
- mItemLayout.setVisibility(View.GONE);
- return;
- } else {
- isDeviceGroup = true;
- }
- } else if (device.hasSubtext()) {
- subtitle = device.getSubtextString();
- boolean isActiveWithOngoingSession =
- device.hasOngoingSession() && (currentlyConnected || isSelected);
- if (isActiveWithOngoingSession) {
- mCurrentActivePosition = position;
- ongoingSessionStatus = new OngoingSessionStatus(
- device.isHostForOngoingSession());
- connectionState = ConnectionState.CONNECTED;
- } else {
- if (currentlyConnected) {
- mCurrentActivePosition = position;
- connectionState = ConnectionState.CONNECTED;
- }
- clickListener = getClickListenerBasedOnSelectionBehavior(device);
- deviceDisabled = clickListener == null;
- deviceStatusIcon = getDeviceStatusIcon(device, device.hasOngoingSession());
- }
- } else if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
- deviceStatusIcon = mContext.getDrawable(R.drawable.media_output_status_failed);
- subtitle = mContext.getString(R.string.media_output_dialog_connect_failed);
- clickListener = v -> onItemClick(v, device);
- } else if (device.getState() == MediaDeviceState.STATE_GROUPING) {
- connectionState = ConnectionState.CONNECTING;
- } else if (mController.getSelectedMediaDevice().size() > 1 && isSelected) {
- // selected device in group
- groupStatus = new GroupStatus(
- true /* selected */,
- isDeselectable /* deselectable */);
- connectionState = ConnectionState.CONNECTED;
- } else if (currentlyConnected) {
- // single selected device
- if (isMutingExpectedDeviceExist
- && !mController.isCurrentConnectedDeviceRemote()) {
- // mark as disconnected and set special click listener
- clickListener = v -> cancelMuteAwaitConnection();
- } else if (device.hasOngoingSession()) {
- mCurrentActivePosition = position;
- ongoingSessionStatus = new OngoingSessionStatus(
- device.isHostForOngoingSession());
- connectionState = ConnectionState.CONNECTED;
- } else if (mController.isCurrentConnectedDeviceRemote()
- && !mController.getSelectableMediaDevice().isEmpty()) {
- //If device is connected and there's other selectable devices, layout as
- // one of selected devices.
- groupStatus = new GroupStatus(
- true /* selected */,
- isDeselectable /* isDeselectable */);
- connectionState = ConnectionState.CONNECTED;
- } else {
- mCurrentActivePosition = position;
- connectionState = ConnectionState.CONNECTED;
- }
- } else if (isSelectable) {
- //groupable device
- groupStatus = new GroupStatus(false /* selected */, true /* deselectable */);
- if (!Flags.disableTransferWhenAppsDoNotSupport()
- || isTransferable
- || hasRouteListingPreferenceItem) {
- clickListener = v -> onItemClick(v, device);
- }
- deviceDisabled = clickListener == null;
- } else {
- deviceStatusIcon = getDeviceStatusIcon(device, device.hasOngoingSession());
- clickListener = getClickListenerBasedOnSelectionBehavior(device);
- deviceDisabled = clickListener == null;
- }
- }
-
- if (isDeviceGroup) {
- String sessionName = mController.getSessionName() == null ? ""
- : mController.getSessionName().toString();
- updateTitle(sessionName);
- updateUnmutedVolumeIcon(null /* device */);
- updateGroupSeekBar(getGroupItemContentDescription(sessionName));
- updateEndAreaForDeviceGroup();
- updateItemBackground(ConnectionState.CONNECTED);
- } else {
- updateTitle(device.getName());
- updateTitleIcon(device, connectionState, restrictVolumeAdjustment);
- updateSeekBar(device, connectionState, restrictVolumeAdjustment,
- getDeviceItemContentDescription(device));
- updateEndArea(device, connectionState, groupStatus, ongoingSessionStatus);
- updateLoadingIndicator(connectionState);
- updateFullItemClickListener(clickListener);
- updateContentAlpha(deviceDisabled);
- updateSubtitle(subtitle);
- updateDeviceStatusIcon(deviceStatusIcon);
- updateItemBackground(connectionState);
- }
- }
-
- /** Renders the right side round pill button / checkbox. */
- private void updateEndArea(@NonNull MediaDevice device, ConnectionState connectionState,
- @Nullable GroupStatus groupStatus,
- @Nullable OngoingSessionStatus ongoingSessionStatus) {
- boolean showEndArea = false;
- boolean isCheckbox = false;
- // If both group status and the ongoing session status are present, only the ongoing
- // session controls are displayed. The current layout design doesn't allow both group
- // and ongoing session controls to be rendered simultaneously.
- if (ongoingSessionStatus != null && connectionState == ConnectionState.CONNECTED) {
- showEndArea = true;
- updateEndAreaForOngoingSession(device, ongoingSessionStatus.host());
- } else if (groupStatus != null && shouldShowGroupCheckbox(groupStatus)) {
- showEndArea = true;
- isCheckbox = true;
- updateEndAreaForGroupCheckBox(device, groupStatus);
- }
- updateEndAreaVisibility(showEndArea, isCheckbox);
- }
-
- private boolean shouldShowGroupCheckbox(@NonNull GroupStatus groupStatus) {
- if (Flags.enableOutputSwitcherDeviceGrouping()) {
- return isGroupCheckboxEnabled(groupStatus);
- }
- return true;
- }
-
- private boolean isGroupCheckboxEnabled(@NonNull GroupStatus groupStatus) {
- boolean disabled = groupStatus.selected() && !groupStatus.deselectable();
- return !disabled;
- }
-
- public void setCheckBoxColor(CheckBox checkBox, int color) {
- int[][] states = {{android.R.attr.state_checked}, {}};
- int[] colors = {color, color};
- CompoundButtonCompat.setButtonTintList(checkBox, new
- ColorStateList(states, colors));
- }
-
- private void updateContentAlpha(boolean deviceDisabled) {
- float alphaValue = deviceDisabled ? DEVICE_DISABLED_ALPHA : DEVICE_ACTIVE_ALPHA;
- mTitleIcon.setAlpha(alphaValue);
- mTitleText.setAlpha(alphaValue);
- mSubTitleText.setAlpha(alphaValue);
- mStatusIcon.setAlpha(alphaValue);
- }
-
- private void updateEndAreaForDeviceGroup() {
- updateEndAreaWithIcon(
- v -> {
- mShouldGroupSelectedMediaItems = false;
- notifyDataSetChanged();
- },
- R.drawable.media_output_item_expand_group,
- R.string.accessibility_expand_group);
- updateEndAreaVisibility(true /* showEndArea */, false /* isCheckbox */);
- }
-
- private void updateEndAreaForOngoingSession(@NonNull MediaDevice device, boolean isHost) {
- updateEndAreaWithIcon(
- v -> mController.tryToLaunchInAppRoutingIntent(device.getId(), v),
- isHost ? R.drawable.media_output_status_edit_session
- : R.drawable.ic_sound_bars_anim,
- R.string.accessibility_open_application);
- }
-
- private void updateEndAreaWithIcon(View.OnClickListener clickListener,
- @DrawableRes int iconDrawableId,
- @StringRes int accessibilityStringId) {
- updateEndAreaColor(mController.getColorSeekbarProgress());
- mEndClickIcon.setImageTintList(
- ColorStateList.valueOf(mController.getColorItemContent()));
- mEndClickIcon.setOnClickListener(clickListener);
- mEndTouchArea.setOnClickListener(v -> mEndClickIcon.performClick());
- Drawable drawable = mContext.getDrawable(iconDrawableId);
- mEndClickIcon.setImageDrawable(drawable);
- if (drawable instanceof AnimatedVectorDrawable) {
- ((AnimatedVectorDrawable) drawable).start();
- }
- if (Flags.enableOutputSwitcherDeviceGrouping()) {
- mEndClickIcon.setContentDescription(mContext.getString(accessibilityStringId));
- }
- }
-
- public void updateEndAreaColor(int color) {
- mEndTouchArea.setBackgroundTintList(
- ColorStateList.valueOf(color));
- }
-
- @Nullable
- private View.OnClickListener getClickListenerBasedOnSelectionBehavior(
- @NonNull MediaDevice device) {
- return Api34Impl.getClickListenerBasedOnSelectionBehavior(
- device, mController, v -> onItemClick(v, device));
- }
-
- @Nullable
- private Drawable getDeviceStatusIcon(MediaDevice device, boolean hasOngoingSession) {
- if (hasOngoingSession) {
- return mContext.getDrawable(R.drawable.ic_sound_bars_anim);
- } else {
- return Api34Impl.getDeviceStatusIconBasedOnSelectionBehavior(device, mContext);
- }
- }
-
- void updateDeviceStatusIcon(@Nullable Drawable deviceStatusIcon) {
- if (deviceStatusIcon == null) {
- mStatusIcon.setVisibility(View.GONE);
- } else {
- mStatusIcon.setImageDrawable(deviceStatusIcon);
- mStatusIcon.setImageTintList(
- ColorStateList.valueOf(mController.getColorItemContent()));
- if (deviceStatusIcon instanceof AnimatedVectorDrawable) {
- ((AnimatedVectorDrawable) deviceStatusIcon).start();
- }
- mStatusIcon.setVisibility(View.VISIBLE);
- }
- }
-
- public void updateEndAreaForGroupCheckBox(@NonNull MediaDevice device,
- @NonNull GroupStatus groupStatus) {
- boolean isEnabled = isGroupCheckboxEnabled(groupStatus);
- mEndTouchArea.setOnClickListener(
- isEnabled ? (v) -> mCheckBox.performClick() : null);
- mEndTouchArea.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
- updateEndAreaColor(groupStatus.selected() ? mController.getColorSeekbarProgress()
- : mController.getColorItemBackground());
- mEndTouchArea.setContentDescription(getDeviceItemContentDescription(device));
- mCheckBox.setOnCheckedChangeListener(null);
- mCheckBox.setChecked(groupStatus.selected());
- mCheckBox.setOnCheckedChangeListener(
- isEnabled ? (buttonView, isChecked) -> onGroupActionTriggered(
- !groupStatus.selected(), device) : null);
- mCheckBox.setEnabled(isEnabled);
- setCheckBoxColor(mCheckBox, mController.getColorItemContent());
- }
-
- private void updateFullItemClickListener(@Nullable View.OnClickListener listener) {
- mContainerLayout.setOnClickListener(listener);
- updateIconAreaClickListener(listener);
- }
-
- /** Binds a ViewHolder for a "Connect a device" item. */
- void onBindPairNewDevice() {
- mTitleText.setTextColor(mController.getColorItemContent());
- mCheckBox.setVisibility(View.GONE);
- updateTitle(mContext.getText(R.string.media_output_dialog_pairing_new));
- updateItemBackground(ConnectionState.DISCONNECTED);
- final Drawable addDrawable = mContext.getDrawable(R.drawable.ic_add);
- mTitleIcon.setImageDrawable(addDrawable);
- mTitleIcon.setImageTintList(
- ColorStateList.valueOf(mController.getColorItemContent()));
- mContainerLayout.setOnClickListener(mController::launchBluetoothPairing);
- }
-
- private void onGroupActionTriggered(boolean isChecked, MediaDevice device) {
- disableSeekBar();
- if (isChecked && isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
- mController.addDeviceToPlayMedia(device);
- } else if (!isChecked && isDeviceIncluded(mController.getDeselectableMediaDevice(),
- device)) {
- mController.removeDeviceFromPlayMedia(device);
- }
- }
-
- private void onItemClick(View view, MediaDevice device) {
- if (mController.isCurrentOutputDeviceHasSessionOngoing()) {
- showCustomEndSessionDialog(device);
- } else {
- transferOutput(device);
- }
- }
-
- private void transferOutput(MediaDevice device) {
- if (mController.isAnyDeviceTransferring()) {
- return;
- }
- if (isCurrentlyConnected(device)) {
- Log.d(TAG, "This device is already connected! : " + device.getName());
- return;
- }
- mController.setTemporaryAllowListExceptionIfNeeded(device);
- mCurrentActivePosition = -1;
- mController.connectDevice(device);
- device.setState(MediaDeviceState.STATE_CONNECTING);
- notifyDataSetChanged();
- }
-
- @VisibleForTesting
- void showCustomEndSessionDialog(MediaDevice device) {
- MediaSessionReleaseDialog mediaSessionReleaseDialog = new MediaSessionReleaseDialog(
- mContext, () -> transferOutput(device), mController.getColorButtonBackground(),
- mController.getColorItemContent());
- mediaSessionReleaseDialog.show();
- }
-
- private void cancelMuteAwaitConnection() {
- mController.cancelMuteAwaitConnection();
- notifyDataSetChanged();
- }
-
- private String getDeviceItemContentDescription(@NonNull MediaDevice device) {
- return mContext.getString(
- device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE
- ? R.string.accessibility_bluetooth_name
- : R.string.accessibility_cast_name, device.getName());
- }
-
- private String getGroupItemContentDescription(String sessionName) {
- return mContext.getString(R.string.accessibility_cast_name, sessionName);
- }
- }
-
- class MediaGroupDividerViewHolder extends RecyclerView.ViewHolder {
- final TextView mTitleText;
-
- MediaGroupDividerViewHolder(@NonNull View itemView) {
- super(itemView);
- mTitleText = itemView.requireViewById(R.id.title);
- }
-
- void onBind(String groupDividerTitle) {
- mTitleText.setTextColor(mController.getColorItemContent());
- mTitleText.setText(groupDividerTitle);
- }
- }
-
- @RequiresApi(34)
- private static class Api34Impl {
- @DoNotInline
- static View.OnClickListener getClickListenerBasedOnSelectionBehavior(
- MediaDevice device,
- MediaSwitchingController controller,
- View.OnClickListener defaultTransferListener) {
- switch (device.getSelectionBehavior()) {
- case SELECTION_BEHAVIOR_NONE:
- return null;
- case SELECTION_BEHAVIOR_TRANSFER:
- return defaultTransferListener;
- case SELECTION_BEHAVIOR_GO_TO_APP:
- return v -> controller.tryToLaunchInAppRoutingIntent(device.getId(), v);
- }
- return defaultTransferListener;
- }
-
- @DoNotInline
- @Nullable
- static Drawable getDeviceStatusIconBasedOnSelectionBehavior(MediaDevice device,
- Context context) {
- switch (device.getSelectionBehavior()) {
- case SELECTION_BEHAVIOR_NONE:
- return context.getDrawable(R.drawable.media_output_status_failed);
- case SELECTION_BEHAVIOR_TRANSFER:
- return null;
- case SELECTION_BEHAVIOR_GO_TO_APP:
- return context.getDrawable(R.drawable.media_output_status_help);
- }
- return null;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java
new file mode 100644
index 000000000000..c58ba377fb68
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterBase.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.dialog;
+
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_GO_TO_APP;
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_NONE;
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+
+import androidx.annotation.DoNotInline;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.media.flags.Flags;
+import com.android.settingslib.media.LocalMediaManager.MediaDeviceState;
+import com.android.settingslib.media.MediaDevice;
+import com.android.systemui.res.R;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * A parent RecyclerView adapter for the media output dialog device list. This class doesn't
+ * manipulate the layout directly.
+ */
+public abstract class MediaOutputAdapterBase extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ record OngoingSessionStatus(boolean host) {}
+
+ record GroupStatus(Boolean selected, Boolean deselectable) {}
+
+ enum ConnectionState {
+ CONNECTED,
+ CONNECTING,
+ DISCONNECTED,
+ }
+
+ protected final MediaSwitchingController mController;
+ private int mCurrentActivePosition;
+ private boolean mIsDragging;
+ private static final String TAG = "MediaOutputAdapterBase";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ protected final List<MediaItem> mMediaItemList = new CopyOnWriteArrayList<>();
+ private boolean mShouldGroupSelectedMediaItems = Flags.enableOutputSwitcherDeviceGrouping();
+
+ public MediaOutputAdapterBase(MediaSwitchingController controller) {
+ mController = controller;
+ mCurrentActivePosition = -1;
+ mIsDragging = false;
+ setHasStableIds(true);
+ }
+
+ boolean isCurrentlyConnected(MediaDevice device) {
+ return TextUtils.equals(device.getId(),
+ mController.getCurrentConnectedMediaDevice().getId())
+ || (mController.getSelectedMediaDevice().size() == 1
+ && isDeviceIncluded(mController.getSelectedMediaDevice(), device));
+ }
+
+ boolean isDeviceIncluded(List<MediaDevice> deviceList, MediaDevice targetDevice) {
+ for (MediaDevice device : deviceList) {
+ if (TextUtils.equals(device.getId(), targetDevice.getId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean isDragging() {
+ return mIsDragging;
+ }
+
+ void setIsDragging(boolean isDragging) {
+ mIsDragging = isDragging;
+ }
+
+ int getCurrentActivePosition() {
+ return mCurrentActivePosition;
+ }
+
+ /** Refreshes the RecyclerView dataset and forces re-render. */
+ public void updateItems() {
+ mMediaItemList.clear();
+ mMediaItemList.addAll(mController.getMediaItemList());
+ if (mShouldGroupSelectedMediaItems) {
+ if (mController.getSelectedMediaDevice().size() == 1) {
+ // Don't group devices if initially there isn't more than one selected.
+ mShouldGroupSelectedMediaItems = false;
+ }
+ }
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ if (position >= mMediaItemList.size()) {
+ Log.d(TAG, "Incorrect position for item id: " + position);
+ return position;
+ }
+ MediaItem currentMediaItem = mMediaItemList.get(position);
+ return currentMediaItem.getMediaDevice().isPresent()
+ ? currentMediaItem.getMediaDevice().get().getId().hashCode()
+ : position;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (position >= mMediaItemList.size()) {
+ Log.d(TAG, "Incorrect position for item type: " + position);
+ return MediaItem.MediaItemType.TYPE_GROUP_DIVIDER;
+ }
+ return mMediaItemList.get(position).getMediaItemType();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mMediaItemList.size();
+ }
+
+ abstract class MediaDeviceViewHolderBase extends RecyclerView.ViewHolder {
+
+ Context mContext;
+
+ MediaDeviceViewHolderBase(View view, Context context) {
+ super(view);
+ mContext = context;
+ }
+
+ void renderItem(MediaItem mediaItem, int position) {
+ MediaDevice device = mediaItem.getMediaDevice().get();
+ boolean isMutingExpectedDeviceExist = mController.hasMutingExpectedDevice();
+ final boolean currentlyConnected = isCurrentlyConnected(device);
+ boolean isSelected = isDeviceIncluded(mController.getSelectedMediaDevice(), device);
+ boolean isDeselectable =
+ isDeviceIncluded(mController.getDeselectableMediaDevice(), device);
+ boolean isSelectable = isDeviceIncluded(mController.getSelectableMediaDevice(), device);
+ boolean isTransferable =
+ isDeviceIncluded(mController.getTransferableMediaDevices(), device);
+ boolean hasRouteListingPreferenceItem = device.hasRouteListingPreferenceItem();
+
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "["
+ + position
+ + "] "
+ + device.getName()
+ + " ["
+ + (isDeselectable ? "deselectable" : "")
+ + "] ["
+ + (isSelected ? "selected" : "")
+ + "] ["
+ + (isSelectable ? "selectable" : "")
+ + "] ["
+ + (isTransferable ? "transferable" : "")
+ + "] ["
+ + (hasRouteListingPreferenceItem ? "hasListingPreference" : "")
+ + "]");
+ }
+
+ boolean isDeviceGroup = false;
+ boolean hideGroupItem = false;
+ GroupStatus groupStatus = null;
+ OngoingSessionStatus ongoingSessionStatus = null;
+ ConnectionState connectionState = ConnectionState.DISCONNECTED;
+ boolean restrictVolumeAdjustment = mController.hasAdjustVolumeUserRestriction();
+ String subtitle = null;
+ Drawable deviceStatusIcon = null;
+ boolean deviceDisabled = false;
+ View.OnClickListener clickListener = null;
+
+ if (mCurrentActivePosition == position) {
+ mCurrentActivePosition = -1;
+ }
+
+ if (mController.isAnyDeviceTransferring()) {
+ if (device.getState() == MediaDeviceState.STATE_CONNECTING) {
+ connectionState = ConnectionState.CONNECTING;
+ }
+ } else {
+ // Set different layout for each device
+ if (device.isMutingExpectedDevice()
+ && !mController.isCurrentConnectedDeviceRemote()) {
+ connectionState = ConnectionState.CONNECTED;
+ restrictVolumeAdjustment = true;
+ clickListener = v -> onItemClick(v, device);
+ } else if (currentlyConnected && isMutingExpectedDeviceExist
+ && !mController.isCurrentConnectedDeviceRemote()) {
+ // mark as disconnected and set special click listener
+ clickListener = v -> cancelMuteAwaitConnection();
+ } else if (device.getState() == MediaDeviceState.STATE_GROUPING) {
+ connectionState = ConnectionState.CONNECTING;
+ } else if (mShouldGroupSelectedMediaItems && hasMultipleSelectedDevices()
+ && isSelected) {
+ if (mediaItem.isFirstDeviceInGroup()) {
+ isDeviceGroup = true;
+ } else {
+ hideGroupItem = true;
+ }
+ } else { // A connected or disconnected device.
+ subtitle = device.hasSubtext() ? device.getSubtextString() : null;
+ ongoingSessionStatus = getOngoingSessionStatus(device);
+ groupStatus = getGroupStatus(isSelected, isSelectable, isDeselectable);
+
+ if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
+ deviceStatusIcon = mContext.getDrawable(
+ R.drawable.media_output_status_failed);
+ subtitle = mContext.getString(R.string.media_output_dialog_connect_failed);
+ clickListener = v -> onItemClick(v, device);
+ } else if (currentlyConnected || isSelected) {
+ connectionState = ConnectionState.CONNECTED;
+ } else { // disconnected
+ if (isSelectable) { // groupable device
+ if (!Flags.disableTransferWhenAppsDoNotSupport() || isTransferable
+ || hasRouteListingPreferenceItem) {
+ clickListener = v -> onItemClick(v, device);
+ }
+ } else {
+ deviceStatusIcon = getDeviceStatusIcon(device,
+ device.hasOngoingSession());
+ clickListener = getClickListenerBasedOnSelectionBehavior(device);
+ }
+ deviceDisabled = clickListener == null;
+ }
+ }
+ }
+
+ if (connectionState == ConnectionState.CONNECTED || isDeviceGroup) {
+ mCurrentActivePosition = position;
+ }
+
+ if (isDeviceGroup) {
+ renderDeviceGroupItem();
+ } else {
+ renderDeviceItem(hideGroupItem, device, connectionState, restrictVolumeAdjustment,
+ groupStatus, ongoingSessionStatus, clickListener, deviceDisabled, subtitle,
+ deviceStatusIcon);
+ }
+ }
+
+ protected abstract void renderDeviceItem(boolean hideGroupItem, MediaDevice device,
+ ConnectionState connectionState, boolean restrictVolumeAdjustment,
+ GroupStatus groupStatus, OngoingSessionStatus ongoingSessionStatus,
+ View.OnClickListener clickListener, boolean deviceDisabled, String subtitle,
+ Drawable deviceStatusIcon);
+
+ protected abstract void renderDeviceGroupItem();
+
+ protected abstract void disableSeekBar();
+
+ private OngoingSessionStatus getOngoingSessionStatus(MediaDevice device) {
+ return device.hasOngoingSession() ? new OngoingSessionStatus(
+ device.isHostForOngoingSession()) : null;
+ }
+
+ private GroupStatus getGroupStatus(boolean isSelected, boolean isSelectable,
+ boolean isDeselectable) {
+ // A device should either be selectable or, when the device selected, the list should
+ // have other selectable or selected devices.
+ boolean selectedWithOtherGroupDevices =
+ isSelected && (hasMultipleSelectedDevices() || hasSelectableDevices());
+ if (isSelectable || selectedWithOtherGroupDevices) {
+ return new GroupStatus(isSelected, isDeselectable);
+ }
+ return null;
+ }
+
+ private boolean hasMultipleSelectedDevices() {
+ return mController.getSelectedMediaDevice().size() > 1;
+ }
+
+ private boolean hasSelectableDevices() {
+ return !mController.getSelectableMediaDevice().isEmpty();
+ }
+
+ @Nullable
+ private View.OnClickListener getClickListenerBasedOnSelectionBehavior(
+ @NonNull MediaDevice device) {
+ return Api34Impl.getClickListenerBasedOnSelectionBehavior(
+ device, mController, v -> onItemClick(v, device));
+ }
+
+ @Nullable
+ private Drawable getDeviceStatusIcon(MediaDevice device, boolean hasOngoingSession) {
+ if (hasOngoingSession) {
+ return mContext.getDrawable(R.drawable.ic_sound_bars_anim);
+ } else {
+ return Api34Impl.getDeviceStatusIconBasedOnSelectionBehavior(device, mContext);
+ }
+ }
+
+ protected void onExpandGroupButtonClicked() {
+ mShouldGroupSelectedMediaItems = false;
+ notifyDataSetChanged();
+ }
+
+ protected void onGroupActionTriggered(boolean isChecked, MediaDevice device) {
+ disableSeekBar();
+ if (isChecked && isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
+ mController.addDeviceToPlayMedia(device);
+ } else if (!isChecked && isDeviceIncluded(mController.getDeselectableMediaDevice(),
+ device)) {
+ mController.removeDeviceFromPlayMedia(device);
+ }
+ }
+
+ private void onItemClick(View view, MediaDevice device) {
+ if (mController.isCurrentOutputDeviceHasSessionOngoing()) {
+ showCustomEndSessionDialog(device);
+ } else {
+ transferOutput(device);
+ }
+ }
+
+ private void transferOutput(MediaDevice device) {
+ if (mController.isAnyDeviceTransferring()) {
+ return;
+ }
+ if (isCurrentlyConnected(device)) {
+ Log.d(TAG, "This device is already connected! : " + device.getName());
+ return;
+ }
+ mController.setTemporaryAllowListExceptionIfNeeded(device);
+ mCurrentActivePosition = -1;
+ mController.connectDevice(device);
+ device.setState(MediaDeviceState.STATE_CONNECTING);
+ notifyDataSetChanged();
+ }
+
+ @VisibleForTesting
+ void showCustomEndSessionDialog(MediaDevice device) {
+ MediaSessionReleaseDialog mediaSessionReleaseDialog = new MediaSessionReleaseDialog(
+ mContext, () -> transferOutput(device), mController.getColorButtonBackground(),
+ mController.getColorItemContent());
+ mediaSessionReleaseDialog.show();
+ }
+
+ private void cancelMuteAwaitConnection() {
+ mController.cancelMuteAwaitConnection();
+ notifyDataSetChanged();
+ }
+
+ protected String getDeviceItemContentDescription(@NonNull MediaDevice device) {
+ return mContext.getString(
+ device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE
+ ? R.string.accessibility_bluetooth_name
+ : R.string.accessibility_cast_name, device.getName());
+ }
+
+ protected String getGroupItemContentDescription(String sessionName) {
+ return mContext.getString(R.string.accessibility_cast_name, sessionName);
+ }
+ }
+
+ @RequiresApi(34)
+ private static class Api34Impl {
+ @DoNotInline
+ static View.OnClickListener getClickListenerBasedOnSelectionBehavior(
+ MediaDevice device,
+ MediaSwitchingController controller,
+ View.OnClickListener defaultTransferListener) {
+ switch (device.getSelectionBehavior()) {
+ case SELECTION_BEHAVIOR_NONE:
+ return null;
+ case SELECTION_BEHAVIOR_TRANSFER:
+ return defaultTransferListener;
+ case SELECTION_BEHAVIOR_GO_TO_APP:
+ return v -> controller.tryToLaunchInAppRoutingIntent(device.getId(), v);
+ }
+ return defaultTransferListener;
+ }
+
+ @DoNotInline
+ @Nullable
+ static Drawable getDeviceStatusIconBasedOnSelectionBehavior(MediaDevice device,
+ Context context) {
+ switch (device.getSelectionBehavior()) {
+ case SELECTION_BEHAVIOR_NONE:
+ return context.getDrawable(R.drawable.media_output_status_failed);
+ case SELECTION_BEHAVIOR_TRANSFER:
+ return null;
+ case SELECTION_BEHAVIOR_GO_TO_APP:
+ return context.getDrawable(R.drawable.media_output_status_help);
+ }
+ return null;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
index f97b3d3d5e38..565b2e41f75a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
@@ -18,14 +18,18 @@ package com.android.systemui.media.dialog;
import android.animation.Animator;
import android.animation.ValueAnimator;
-import android.app.WallpaperColors;
+import android.annotation.DrawableRes;
+import android.annotation.StringRes;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.ClipDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.Icon;
import android.graphics.drawable.LayerDrawable;
import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -40,6 +44,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.core.widget.CompoundButtonCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.android.media.flags.Flags;
@@ -48,82 +53,67 @@ import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.res.R;
-import java.util.List;
-
/**
- * Base adapter for media output dialog.
+ * A RecyclerView adapter for the legacy UI media output dialog device list.
*/
-public abstract class MediaOutputBaseAdapter extends
- RecyclerView.Adapter<RecyclerView.ViewHolder> {
-
- record OngoingSessionStatus(boolean host) {}
-
- record GroupStatus(Boolean selected, Boolean deselectable) {}
-
- enum ConnectionState {
- CONNECTED,
- CONNECTING,
- DISCONNECTED,
- }
-
- protected final MediaSwitchingController mController;
+public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase {
+ private static final String TAG = "MediaOutputAdapterL";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int UNMUTE_DEFAULT_VOLUME = 2;
-
- Context mContext;
+ private static final float DEVICE_DISABLED_ALPHA = 0.5f;
+ private static final float DEVICE_ACTIVE_ALPHA = 1f;
View mHolderView;
- boolean mIsDragging;
- int mCurrentActivePosition;
private boolean mIsInitVolumeFirstTime;
- public MediaOutputBaseAdapter(MediaSwitchingController controller) {
- mController = controller;
- mIsDragging = false;
- mCurrentActivePosition = -1;
+ public MediaOutputAdapterLegacy(MediaSwitchingController controller) {
+ super(controller);
mIsInitVolumeFirstTime = true;
}
- /**
- * Refresh current dataset
- */
- public abstract void updateItems();
-
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
- mContext = viewGroup.getContext();
- mHolderView = LayoutInflater.from(mContext).inflate(MediaItem.getMediaLayoutId(viewType),
- viewGroup, false);
- return null;
- }
-
- void updateColorScheme(WallpaperColors wallpaperColors, boolean isDarkTheme) {
- mController.setCurrentColorScheme(wallpaperColors, isDarkTheme);
- }
+ Context context = viewGroup.getContext();
+ mHolderView = LayoutInflater.from(viewGroup.getContext()).inflate(
+ MediaItem.getMediaLayoutId(viewType),
+ viewGroup, false);
- boolean isCurrentlyConnected(MediaDevice device) {
- return TextUtils.equals(device.getId(),
- mController.getCurrentConnectedMediaDevice().getId())
- || (mController.getSelectedMediaDevice().size() == 1
- && isDeviceIncluded(mController.getSelectedMediaDevice(), device));
+ switch (viewType) {
+ case MediaItem.MediaItemType.TYPE_GROUP_DIVIDER:
+ return new MediaGroupDividerViewHolderLegacy(mHolderView);
+ case MediaItem.MediaItemType.TYPE_PAIR_NEW_DEVICE:
+ case MediaItem.MediaItemType.TYPE_DEVICE:
+ default:
+ return new MediaDeviceViewHolderLegacy(mHolderView, context);
+ }
}
- boolean isDeviceIncluded(List<MediaDevice> deviceList, MediaDevice targetDevice) {
- for (MediaDevice device : deviceList) {
- if (TextUtils.equals(device.getId(), targetDevice.getId())) {
- return true;
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
+ if (position >= getItemCount()) {
+ if (DEBUG) {
+ Log.d(TAG, "Incorrect position: " + position + " list size: "
+ + getItemCount());
}
+ return;
+ }
+ MediaItem currentMediaItem = mMediaItemList.get(position);
+ switch (currentMediaItem.getMediaItemType()) {
+ case MediaItem.MediaItemType.TYPE_GROUP_DIVIDER:
+ ((MediaGroupDividerViewHolderLegacy) viewHolder).onBind(
+ currentMediaItem.getTitle());
+ break;
+ case MediaItem.MediaItemType.TYPE_PAIR_NEW_DEVICE:
+ ((MediaDeviceViewHolderLegacy) viewHolder).onBindPairNewDevice();
+ break;
+ case MediaItem.MediaItemType.TYPE_DEVICE:
+ ((MediaDeviceViewHolderLegacy) viewHolder).onBindDevice(currentMediaItem, position);
+ break;
+ default:
+ Log.d(TAG, "Incorrect position: " + position);
}
- return false;
- }
-
- boolean isDragging() {
- return mIsDragging;
- }
-
- int getCurrentActivePosition() {
- return mCurrentActivePosition;
}
public MediaSwitchingController getController() {
@@ -133,7 +123,7 @@ public abstract class MediaOutputBaseAdapter extends
/**
* ViewHolder for binding device view.
*/
- abstract class MediaDeviceBaseViewHolder extends RecyclerView.ViewHolder {
+ class MediaDeviceViewHolderLegacy extends MediaDeviceViewHolderBase {
private static final int ANIM_DURATION = 500;
@@ -158,8 +148,8 @@ public abstract class MediaOutputBaseAdapter extends
private ValueAnimator mVolumeAnimator;
private int mLatestUpdateVolume = -1;
- MediaDeviceBaseViewHolder(View view) {
- super(view);
+ MediaDeviceViewHolderLegacy(View view, Context context) {
+ super(view, context);
mContainerLayout = view.requireViewById(R.id.device_container);
mItemLayout = view.requireViewById(R.id.item_layout);
mTitleText = view.requireViewById(R.id.title);
@@ -180,8 +170,10 @@ public abstract class MediaOutputBaseAdapter extends
initAnimator();
}
- void onBind(MediaDevice device, int position) {
+ void onBindDevice(MediaItem mediaItem, int position) {
+ MediaDevice device = mediaItem.getMediaDevice().get();
mDeviceId = device.getId();
+ mItemLayout.setVisibility(View.VISIBLE);
mCheckBox.setVisibility(View.GONE);
mStatusIcon.setVisibility(View.GONE);
mEndTouchArea.setVisibility(View.GONE);
@@ -196,6 +188,54 @@ public abstract class MediaOutputBaseAdapter extends
mSeekBar.setProgressTintList(
ColorStateList.valueOf(mController.getColorSeekbarProgress()));
enableFocusPropertyForView(mContainerLayout);
+ renderItem(mediaItem, position);
+ }
+
+ /** Binds a ViewHolder for a "Connect a device" item. */
+ void onBindPairNewDevice() {
+ mTitleText.setTextColor(mController.getColorItemContent());
+ mCheckBox.setVisibility(View.GONE);
+ updateTitle(mContext.getText(R.string.media_output_dialog_pairing_new));
+ updateItemBackground(ConnectionState.DISCONNECTED);
+ final Drawable addDrawable = mContext.getDrawable(R.drawable.ic_add);
+ mTitleIcon.setImageDrawable(addDrawable);
+ mTitleIcon.setImageTintList(
+ ColorStateList.valueOf(mController.getColorItemContent()));
+ mContainerLayout.setOnClickListener(mController::launchBluetoothPairing);
+ }
+
+ @Override
+ protected void renderDeviceItem(boolean hideGroupItem, MediaDevice device,
+ ConnectionState connectionState, boolean restrictVolumeAdjustment,
+ GroupStatus groupStatus, OngoingSessionStatus ongoingSessionStatus,
+ View.OnClickListener clickListener, boolean deviceDisabled, String subtitle,
+ Drawable deviceStatusIcon) {
+ if (hideGroupItem) {
+ mItemLayout.setVisibility(View.GONE);
+ return;
+ }
+ updateTitle(device.getName());
+ updateTitleIcon(device, connectionState, restrictVolumeAdjustment);
+ updateSeekBar(device, connectionState, restrictVolumeAdjustment,
+ getDeviceItemContentDescription(device));
+ updateEndArea(device, connectionState, groupStatus, ongoingSessionStatus);
+ updateLoadingIndicator(connectionState);
+ updateFullItemClickListener(clickListener);
+ updateContentAlpha(deviceDisabled);
+ updateSubtitle(subtitle);
+ updateDeviceStatusIcon(deviceStatusIcon);
+ updateItemBackground(connectionState);
+ }
+
+ @Override
+ protected void renderDeviceGroupItem() {
+ String sessionName = mController.getSessionName() == null ? ""
+ : mController.getSessionName().toString();
+ updateTitle(sessionName);
+ updateUnmutedVolumeIcon(null /* device */);
+ updateGroupSeekBar(getGroupItemContentDescription(sessionName));
+ updateEndAreaForDeviceGroup();
+ updateItemBackground(ConnectionState.CONNECTED);
}
void updateTitle(CharSequence title) {
@@ -303,7 +343,7 @@ public abstract class MediaOutputBaseAdapter extends
private void initializeSeekbarVolume(
@Nullable MediaDevice device, int currentVolume,
boolean isCurrentSeekbarInvisible) {
- if (!mIsDragging) {
+ if (!isDragging()) {
if (mSeekBar.getVolume() != currentVolume && (mLatestUpdateVolume == -1
|| currentVolume == mLatestUpdateVolume)) {
// Update only if volume of device and value of volume bar doesn't match.
@@ -459,6 +499,132 @@ public abstract class MediaOutputBaseAdapter extends
: R.drawable.media_output_icon_volume;
}
+ private void updateContentAlpha(boolean deviceDisabled) {
+ float alphaValue = deviceDisabled ? DEVICE_DISABLED_ALPHA : DEVICE_ACTIVE_ALPHA;
+ mTitleIcon.setAlpha(alphaValue);
+ mTitleText.setAlpha(alphaValue);
+ mSubTitleText.setAlpha(alphaValue);
+ mStatusIcon.setAlpha(alphaValue);
+ }
+
+ private void updateDeviceStatusIcon(@Nullable Drawable deviceStatusIcon) {
+ if (deviceStatusIcon == null) {
+ mStatusIcon.setVisibility(View.GONE);
+ } else {
+ mStatusIcon.setImageDrawable(deviceStatusIcon);
+ mStatusIcon.setImageTintList(
+ ColorStateList.valueOf(mController.getColorItemContent()));
+ if (deviceStatusIcon instanceof AnimatedVectorDrawable) {
+ ((AnimatedVectorDrawable) deviceStatusIcon).start();
+ }
+ mStatusIcon.setVisibility(View.VISIBLE);
+ }
+ }
+
+
+ /** Renders the right side round pill button / checkbox. */
+ private void updateEndArea(@NonNull MediaDevice device, ConnectionState connectionState,
+ @Nullable GroupStatus groupStatus,
+ @Nullable OngoingSessionStatus ongoingSessionStatus) {
+ boolean showEndArea = false;
+ boolean isCheckbox = false;
+ // If both group status and the ongoing session status are present, only the ongoing
+ // session controls are displayed. The current layout design doesn't allow both group
+ // and ongoing session controls to be rendered simultaneously.
+ if (ongoingSessionStatus != null && connectionState == ConnectionState.CONNECTED) {
+ showEndArea = true;
+ updateEndAreaForOngoingSession(device, ongoingSessionStatus.host());
+ } else if (groupStatus != null && shouldShowGroupCheckbox(groupStatus)) {
+ showEndArea = true;
+ isCheckbox = true;
+ updateEndAreaForGroupCheckBox(device, groupStatus);
+ }
+ updateEndAreaVisibility(showEndArea, isCheckbox);
+ }
+
+ private void updateEndAreaForDeviceGroup() {
+ updateEndAreaWithIcon(
+ v -> {
+ onExpandGroupButtonClicked();
+ },
+ R.drawable.media_output_item_expand_group,
+ R.string.accessibility_expand_group);
+ updateEndAreaVisibility(true /* showEndArea */, false /* isCheckbox */);
+ }
+
+ private void updateEndAreaForOngoingSession(@NonNull MediaDevice device, boolean isHost) {
+ updateEndAreaWithIcon(
+ v -> mController.tryToLaunchInAppRoutingIntent(device.getId(), v),
+ isHost ? R.drawable.media_output_status_edit_session
+ : R.drawable.ic_sound_bars_anim,
+ R.string.accessibility_open_application);
+ }
+
+ private void updateEndAreaWithIcon(View.OnClickListener clickListener,
+ @DrawableRes int iconDrawableId,
+ @StringRes int accessibilityStringId) {
+ updateEndAreaColor(mController.getColorSeekbarProgress());
+ mEndClickIcon.setImageTintList(
+ ColorStateList.valueOf(mController.getColorItemContent()));
+ mEndClickIcon.setOnClickListener(clickListener);
+ mEndTouchArea.setOnClickListener(v -> mEndClickIcon.performClick());
+ Drawable drawable = mContext.getDrawable(iconDrawableId);
+ mEndClickIcon.setImageDrawable(drawable);
+ if (drawable instanceof AnimatedVectorDrawable) {
+ ((AnimatedVectorDrawable) drawable).start();
+ }
+ if (Flags.enableOutputSwitcherDeviceGrouping()) {
+ mEndClickIcon.setContentDescription(mContext.getString(accessibilityStringId));
+ }
+ }
+
+ private void updateEndAreaForGroupCheckBox(@NonNull MediaDevice device,
+ @NonNull GroupStatus groupStatus) {
+ boolean isEnabled = isGroupCheckboxEnabled(groupStatus);
+ mEndTouchArea.setOnClickListener(
+ isEnabled ? (v) -> mCheckBox.performClick() : null);
+ mEndTouchArea.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ updateEndAreaColor(groupStatus.selected() ? mController.getColorSeekbarProgress()
+ : mController.getColorItemBackground());
+ mEndTouchArea.setContentDescription(getDeviceItemContentDescription(device));
+ mCheckBox.setOnCheckedChangeListener(null);
+ mCheckBox.setChecked(groupStatus.selected());
+ mCheckBox.setOnCheckedChangeListener(
+ isEnabled ? (buttonView, isChecked) -> onGroupActionTriggered(
+ !groupStatus.selected(), device) : null);
+ mCheckBox.setEnabled(isEnabled);
+ setCheckBoxColor(mCheckBox, mController.getColorItemContent());
+ }
+
+ private void setCheckBoxColor(CheckBox checkBox, int color) {
+ int[][] states = {{android.R.attr.state_checked}, {}};
+ int[] colors = {color, color};
+ CompoundButtonCompat.setButtonTintList(checkBox, new
+ ColorStateList(states, colors));
+ }
+
+ private boolean shouldShowGroupCheckbox(@NonNull GroupStatus groupStatus) {
+ if (Flags.enableOutputSwitcherDeviceGrouping()) {
+ return isGroupCheckboxEnabled(groupStatus);
+ }
+ return true;
+ }
+
+ private boolean isGroupCheckboxEnabled(@NonNull GroupStatus groupStatus) {
+ boolean disabled = groupStatus.selected() && !groupStatus.deselectable();
+ return !disabled;
+ }
+
+ private void updateEndAreaColor(int color) {
+ mEndTouchArea.setBackgroundTintList(
+ ColorStateList.valueOf(color));
+ }
+
+ private void updateFullItemClickListener(@Nullable View.OnClickListener listener) {
+ mContainerLayout.setOnClickListener(listener);
+ updateIconAreaClickListener(listener);
+ }
+
void updateIconAreaClickListener(@Nullable View.OnClickListener listener) {
mIconAreaLayout.setOnClickListener(listener);
}
@@ -498,6 +664,7 @@ public abstract class MediaOutputBaseAdapter extends
});
}
+ @Override
protected void disableSeekBar() {
mSeekBar.setEnabled(false);
mSeekBar.setOnTouchListener((v, event) -> true);
@@ -589,7 +756,7 @@ public abstract class MediaOutputBaseAdapter extends
int currentVolume = MediaOutputSeekbar.scaleProgressToVolume(
seekBar.getProgress());
mStartFromMute = (currentVolume == 0);
- mIsDragging = true;
+ setIsDragging(true);
}
@Override
@@ -604,11 +771,25 @@ public abstract class MediaOutputBaseAdapter extends
}
mTitleIcon.setVisibility(View.VISIBLE);
mVolumeValueText.setVisibility(View.GONE);
- mIsDragging = false;
+ setIsDragging(false);
}
protected boolean shouldHandleProgressChanged() {
return mMediaDevice != null;
}
};
}
+
+ class MediaGroupDividerViewHolderLegacy extends RecyclerView.ViewHolder {
+ final TextView mTitleText;
+
+ MediaGroupDividerViewHolderLegacy(@NonNull View itemView) {
+ super(itemView);
+ mTitleText = itemView.requireViewById(R.id.title);
+ }
+
+ void onBind(String groupDividerTitle) {
+ mTitleText.setTextColor(mController.getColorItemContent());
+ mTitleText.setText(groupDividerTitle);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 64256f97fd78..d791361d555f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -105,7 +105,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
private boolean mIsLeBroadcastCallbackRegistered;
private boolean mDismissing;
- MediaOutputBaseAdapter mAdapter;
+ MediaOutputAdapterBase mAdapter;
protected Executor mExecutor;
@@ -342,7 +342,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog
WallpaperColors wallpaperColors = WallpaperColors.fromBitmap(icon.getBitmap());
colorSetUpdated = !wallpaperColors.equals(mWallpaperColors);
if (colorSetUpdated) {
- mAdapter.updateColorScheme(wallpaperColors, isDarkThemeOn);
+ mMediaSwitchingController.setCurrentColorScheme(wallpaperColors, isDarkThemeOn);
updateButtonBackgroundColorFilter();
updateDialogBackgroundColor();
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 9b5b872a00db..9ade9e275ca1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -245,7 +245,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
broadcastSender,
mediaSwitchingController, /* includePlaybackAndAppMetadata */
true);
- mAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
// TODO(b/226710953): Move the part to MediaOutputBaseDialog for every class
// that extends MediaOutputBaseDialog
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index c9af7b322811..2e602be4556e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -53,7 +53,7 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
super(context, broadcastSender, mediaSwitchingController, includePlaybackAndAppMetadata);
mDialogTransitionAnimator = dialogTransitionAnimator;
mUiEventLogger = uiEventLogger;
- mAdapter = new MediaOutputAdapter(mMediaSwitchingController);
+ mAdapter = new MediaOutputAdapterLegacy(mMediaSwitchingController);
if (!aboveStatusbar) {
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
index a0663d72a076..e293e202633e 100644
--- a/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
+++ b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
@@ -25,7 +25,7 @@ object ModesUi {
/** Is the refactor enabled */
@JvmStatic
inline val isEnabled
- get() = Flags.modesApi() && Flags.modesUi()
+ get() = Flags.modesUi()
/**
* Called to ensure code is only run when the flag is enabled. This protects users from the
diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt
index c7b165415aea..c43c1a999fcb 100644
--- a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt
@@ -20,12 +20,15 @@ import androidx.compose.runtime.getValue
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
+import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
+import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.awaitCancellation
@@ -33,6 +36,7 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOf
/**
* Models UI state used to render the content of the notifications shade overlay.
@@ -47,6 +51,8 @@ constructor(
val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
val sceneInteractor: SceneInteractor,
private val shadeInteractor: ShadeInteractor,
+ disableFlagsInteractor: DisableFlagsInteractor,
+ mediaCarouselInteractor: MediaCarouselInteractor,
activeNotificationsInteractor: ActiveNotificationsInteractor,
) : ExclusiveActivatable() {
@@ -69,6 +75,22 @@ constructor(
),
)
+ val showMedia: Boolean by
+ hydrator.hydratedStateOf(
+ traceName = "showMedia",
+ initialValue =
+ disableFlagsInteractor.disableFlags.value.isQuickSettingsEnabled() &&
+ mediaCarouselInteractor.hasActiveMediaOrRecommendation.value,
+ source =
+ disableFlagsInteractor.disableFlags.flatMapLatestConflated {
+ if (it.isQuickSettingsEnabled()) {
+ mediaCarouselInteractor.hasActiveMediaOrRecommendation
+ } else {
+ flowOf(false)
+ }
+ },
+ )
+
override suspend fun onActivated(): Nothing {
coroutineScope {
launch { hydrator.activate() }
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogV2.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogV2.kt
index 57d40638b8df..9117afb1de6f 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogV2.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogV2.kt
@@ -39,6 +39,11 @@ import androidx.annotation.DrawableRes
import androidx.annotation.WorkerThread
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_COLLAPSE
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_EXPAND
+import androidx.core.view.accessibility.AccessibilityViewCommand
+import com.android.systemui.Flags
import com.android.systemui.animation.ViewHierarchyAnimator
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -282,49 +287,95 @@ class PrivacyDialogV2(
val expandToggle =
itemHeader.findViewById<ImageView>(R.id.privacy_dialog_item_header_expand_toggle)!!
- expandToggle.setImageResource(R.drawable.privacy_dialog_expand_toggle_down)
expandToggle.visibility = View.VISIBLE
-
- ViewCompat.replaceAccessibilityAction(
- itemCard,
- AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
- context.getString(R.string.privacy_dialog_expand_action),
- null,
- )
-
val expandedLayout =
itemCard.findViewById<View>(R.id.privacy_dialog_item_header_expanded_layout)!!
expandedLayout.setOnClickListener {
// Stop clicks from propagating
}
- itemCard.setOnClickListener {
- if (expandedLayout.visibility == View.VISIBLE) {
- expandedLayout.visibility = View.GONE
- expandToggle.setImageResource(R.drawable.privacy_dialog_expand_toggle_down)
- ViewCompat.replaceAccessibilityAction(
- it!!,
- AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
- context.getString(R.string.privacy_dialog_expand_action),
- null,
- )
- } else {
- expandedLayout.visibility = View.VISIBLE
- expandToggle.setImageResource(R.drawable.privacy_dialog_expand_toggle_up)
- ViewCompat.replaceAccessibilityAction(
- it!!,
- AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
- context.getString(R.string.privacy_dialog_collapse_action),
- null,
- )
+ if (Flags.expandCollapsePrivacyDialog()) {
+ updateExpansion(ACTION_COLLAPSE, itemCard, expandedLayout, expandToggle)
+
+ itemCard.setOnClickListener {
+ if (expandedLayout.visibility == View.VISIBLE) {
+ updateExpansion(ACTION_COLLAPSE, it!!, expandedLayout, expandToggle)
+ } else {
+ updateExpansion(ACTION_EXPAND, it!!, expandedLayout, expandToggle)
+ }
}
- ViewHierarchyAnimator.animateNextUpdate(
- rootView = window!!.decorView,
- excludedViews = setOf(expandedLayout),
+ } else {
+ expandToggle.setImageResource(R.drawable.privacy_dialog_expand_toggle_down)
+ ViewCompat.replaceAccessibilityAction(
+ itemCard,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ context.getString(R.string.privacy_dialog_expand_action),
+ null,
)
+
+ itemCard.setOnClickListener {
+ if (expandedLayout.visibility == View.VISIBLE) {
+ expandedLayout.visibility = View.GONE
+ expandToggle.setImageResource(R.drawable.privacy_dialog_expand_toggle_down)
+ ViewCompat.replaceAccessibilityAction(
+ it!!,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ context.getString(R.string.privacy_dialog_expand_action),
+ null,
+ )
+ } else {
+ expandedLayout.visibility = View.VISIBLE
+ expandToggle.setImageResource(R.drawable.privacy_dialog_expand_toggle_up)
+ ViewCompat.replaceAccessibilityAction(
+ it!!,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ context.getString(R.string.privacy_dialog_collapse_action),
+ null,
+ )
+ }
+ ViewHierarchyAnimator.animateNextUpdate(
+ rootView = window!!.decorView,
+ excludedViews = setOf(expandedLayout),
+ )
+ }
}
}
+ private fun updateExpansion(
+ newState: AccessibilityActionCompat,
+ itemCard: View,
+ expandedLayout: View,
+ expandToggle: ImageView,
+ ) {
+ expandedLayout.visibility = if (newState == ACTION_COLLAPSE) View.GONE else View.VISIBLE
+ expandToggle.setImageResource(
+ if (newState == ACTION_COLLAPSE) R.drawable.privacy_dialog_expand_toggle_down
+ else R.drawable.privacy_dialog_expand_toggle_up
+ )
+ val accessibilityString =
+ context.getString(
+ if (newState == ACTION_COLLAPSE) R.string.privacy_dialog_expand_action
+ else R.string.privacy_dialog_collapse_action
+ )
+ ViewCompat.replaceAccessibilityAction(
+ itemCard,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
+ accessibilityString,
+ null,
+ )
+ val expandCollapseAccessibilityListener =
+ AccessibilityViewCommand { view: View, _: AccessibilityViewCommand.CommandArguments? ->
+ view.callOnClick()
+ }
+ ViewCompat.replaceAccessibilityAction(
+ itemCard,
+ if (newState == ACTION_COLLAPSE) ACTION_EXPAND else ACTION_COLLAPSE,
+ accessibilityString,
+ expandCollapseAccessibilityListener,
+ )
+ ViewCompat.removeAccessibilityAction(itemCard, newState.id)
+ }
+
private fun updateIconView(iconView: ImageView, indicatorIcon: Drawable, active: Boolean) {
indicatorIcon.setTint(getForegroundColor(active))
val backgroundIcon = getMutableDrawable(R.drawable.privacy_dialog_background_circle)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index cf3b4969b07d..28540d4f1259 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -883,7 +883,7 @@ private suspend fun synchronizeQsState(
var currentTransition: ExpansionTransition? = null
fun snapTo(scene: SceneKey) {
- state.snapToScene(scene)
+ state.snapTo(scene)
currentTransition = null
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
index 7701b9087e23..ebfe101948c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
@@ -34,6 +34,7 @@ import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.clipScrollableContainer
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
@@ -56,14 +57,18 @@ import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.systemGestureExclusion
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Clear
+import androidx.compose.material.icons.filled.Remove
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.LocalMinimumInteractiveComponentSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
@@ -86,9 +91,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.isSpecified
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.onGloballyPositioned
@@ -105,10 +113,13 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
+import androidx.compose.ui.unit.toSize
import androidx.compose.ui.util.fastMap
+import androidx.compose.ui.zIndex
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.animation.bounceable
import com.android.compose.modifiers.height
@@ -131,6 +142,7 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaul
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AUTO_SCROLL_SPEED
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AvailableTilesGridMinHeight
import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.TileBadgeSize
import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState
import com.android.systemui.qs.panels.ui.compose.selection.ResizableTileContainer
import com.android.systemui.qs.panels.ui.compose.selection.ResizingState
@@ -143,6 +155,7 @@ import com.android.systemui.qs.panels.ui.compose.selection.selectableTile
import com.android.systemui.qs.panels.ui.model.GridCell
import com.android.systemui.qs.panels.ui.model.SpacerGridCell
import com.android.systemui.qs.panels.ui.model.TileGridCell
+import com.android.systemui.qs.panels.ui.viewmodel.AvailableEditActions
import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -152,6 +165,7 @@ import kotlin.math.abs
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
object TileType
@@ -232,16 +246,14 @@ fun DefaultEditTileGrid(
// the top bar
.padding(top = innerPadding.calculateTopPadding())
.clipScrollableContainer(Orientation.Vertical)
- .verticalScroll(scrollState),
+ .verticalScroll(scrollState)
+ .dragAndDropRemoveZone(listState, onRemoveTile),
) {
AnimatedContent(
targetState = listState.dragInProgress || selectionState.selected,
label = "QSEditHeader",
) { showRemoveTarget ->
- EditGridHeader(
- Modifier.dragAndDropRemoveZone(listState, onRemoveTile)
- .padding(bottom = 26.dp)
- ) {
+ EditGridHeader(Modifier.padding(bottom = 26.dp)) {
if (showRemoveTarget) {
RemoveTileTarget {
selectionState.selection?.let {
@@ -261,6 +273,7 @@ fun DefaultEditTileGrid(
columns,
largeTilesSpan,
onResize,
+ onRemoveTile,
onSetTiles,
)
@@ -269,7 +282,6 @@ fun DefaultEditTileGrid(
Modifier.fillMaxWidth()
.requiredHeightIn(AvailableTilesGridMinHeight)
.animateContentSize()
- .dragAndDropRemoveZone(listState, onRemoveTile)
) {
// Using the fully qualified name here as a workaround for AnimatedVisibility
// not being available from a Box
@@ -385,6 +397,7 @@ private fun CurrentTilesGrid(
columns: Int,
largeTilesSpan: Int,
onResize: (TileSpec, toIcon: Boolean) -> Unit,
+ onRemoveTile: (TileSpec) -> Unit,
onSetTiles: (List<TileSpec>) -> Unit,
) {
val currentListState by rememberUpdatedState(listState)
@@ -424,8 +437,15 @@ private fun CurrentTilesGrid(
}
.testTag(CURRENT_TILES_GRID_TEST_TAG),
) {
- EditTiles(cells, columns, listState, selectionState, coroutineScope, largeTilesSpan) {
- resizingOperation ->
+ EditTiles(
+ cells,
+ columns,
+ listState,
+ selectionState,
+ coroutineScope,
+ largeTilesSpan,
+ onRemoveTile,
+ ) { resizingOperation ->
when (resizingOperation) {
is TemporaryResizeOperation -> {
currentListState.resizeTile(resizingOperation.spec, resizingOperation.toIcon)
@@ -530,6 +550,7 @@ fun LazyGridScope.EditTiles(
selectionState: MutableSelectionState,
coroutineScope: CoroutineScope,
largeTilesSpan: Int,
+ onRemoveTile: (TileSpec) -> Unit,
onResize: (operation: ResizeOperation) -> Unit,
) {
items(
@@ -558,6 +579,7 @@ fun LazyGridScope.EditTiles(
dragAndDropState = dragAndDropState,
selectionState = selectionState,
onResize = onResize,
+ onRemoveTile = onRemoveTile,
coroutineScope = coroutineScope,
bounceableInfo = cells.bounceableInfo(index, columns),
largeTilesSpan = largeTilesSpan,
@@ -576,6 +598,7 @@ private fun TileGridCell(
dragAndDropState: DragAndDropState,
selectionState: MutableSelectionState,
onResize: (operation: ResizeOperation) -> Unit,
+ onRemoveTile: (TileSpec) -> Unit,
coroutineScope: CoroutineScope,
largeTilesSpan: Int,
bounceableInfo: BounceableInfo,
@@ -583,6 +606,8 @@ private fun TileGridCell(
) {
val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
var selected by remember { mutableStateOf(false) }
+ val showRemovalBadge =
+ !selected && cell.tile.availableEditActions.contains(AvailableEditActions.REMOVE)
val selectionAlpha by
animateFloatAsState(
targetValue = if (selected) 1f else 0f,
@@ -682,6 +707,15 @@ private fun TileGridCell(
) {
EditTile(tile = cell.tile, state = state, progress = progress)
}
+
+ if (showRemovalBadge) {
+ TileBadge(
+ icon = Icons.Default.Remove,
+ contentDescription = stringResource(R.string.qs_customize_remove),
+ ) {
+ onRemoveTile(cell.tile.tileSpec)
+ }
+ }
}
}
@@ -708,27 +742,35 @@ private fun AvailableTileGridCell(
verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top),
modifier = modifier,
) {
- Box(
- Modifier.fillMaxWidth()
- .height(TileHeight)
- .clickable(onClick = onClick, onClickLabel = onClickActionName)
- .semantics(mergeDescendants = true) { this.stateDescription = stateDescription }
- .dragAndDropTileSource(
- SizedTileImpl(cell.tile, cell.width),
- dragAndDropState,
- DragType.Add,
- ) {
- selectionState.unSelect()
- }
- .tileBackground(colors.background)
- .tilePadding()
- ) {
- // Icon
- SmallTileContent(
- iconProvider = { cell.tile.icon },
- color = colors.icon,
- animateToEnd = true,
- modifier = Modifier.align(Alignment.Center),
+ Box {
+ Box(
+ Modifier.fillMaxWidth()
+ .height(TileHeight)
+ .clickable(onClick = onClick, onClickLabel = onClickActionName)
+ .semantics(mergeDescendants = true) { this.stateDescription = stateDescription }
+ .dragAndDropTileSource(
+ SizedTileImpl(cell.tile, cell.width),
+ dragAndDropState,
+ DragType.Add,
+ ) {
+ selectionState.unSelect()
+ }
+ .tileBackground(colors.background)
+ .tilePadding()
+ ) {
+ // Icon
+ SmallTileContent(
+ iconProvider = { cell.tile.icon },
+ color = colors.icon,
+ animateToEnd = true,
+ modifier = Modifier.align(Alignment.Center),
+ )
+ }
+
+ TileBadge(
+ icon = Icons.Default.Add,
+ contentDescription = onClickActionName,
+ onClick = onClick,
)
}
Box(Modifier.fillMaxSize()) {
@@ -745,6 +787,39 @@ private fun AvailableTileGridCell(
}
@Composable
+private fun TileBadge(icon: ImageVector, contentDescription: String?, onClick: () -> Unit) {
+ // Use a higher zIndex than the tile to draw over it, and manually create the touch target as
+ // we're drawing over neighbor tiles as well.
+ val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
+
+ Box(
+ Modifier.zIndex(2f)
+ .layout { measurable, constraints ->
+ val size = minTouchTargetSize.roundToPx()
+ val placeable = measurable.measure(Constraints(size))
+ layout(placeable.width, placeable.height) {
+ val iconRadius = TileBadgeSize.roundToPx() / 2
+ val x = constraints.maxWidth - placeable.width / 2 - iconRadius
+ val y = 0 - placeable.height / 2 + iconRadius
+ placeable.place(x, y)
+ }
+ }
+ .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
+ .pointerInput(Unit) { detectTapGestures { onClick() } }
+ ) {
+ val secondaryColor = MaterialTheme.colorScheme.secondary
+ Icon(
+ icon,
+ contentDescription = contentDescription,
+ modifier =
+ Modifier.size(TileBadgeSize).align(Alignment.Center).drawBehind {
+ drawCircle(secondaryColor)
+ },
+ )
+ }
+}
+
+@Composable
private fun SpacerGridCell(modifier: Modifier = Modifier) {
// By default, spacers are invisible and exist purely to catch drag movements
Box(modifier.height(TileHeight).fillMaxWidth())
@@ -829,6 +904,7 @@ private object EditModeTileDefaults {
const val AUTO_SCROLL_SPEED = 2 // 2ms per pixel
val CurrentTilesGridPadding = 8.dp
val AvailableTilesGridMinHeight = 200.dp
+ val TileBadgeSize = 20.dp
@Composable
fun editTileColors(): TileColors =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
index c1545e1263db..7c472638da63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
@@ -81,7 +81,7 @@ fun ResizableTileContainer(
state = state,
modifier =
// Higher zIndex to make sure the handle is drawn above the content
- Modifier.zIndex(2f),
+ Modifier.zIndex(if (selected) 2f else 1f),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt
index c9a0635021da..61a8fa3d2a6e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt
@@ -55,6 +55,7 @@ object SubtitleArrayMapping {
subtitleIdsMap["font_scaling"] = R.array.tile_states_font_scaling
subtitleIdsMap["hearing_devices"] = R.array.tile_states_hearing_devices
subtitleIdsMap["notes"] = R.array.tile_states_notes
+ subtitleIdsMap["desktopeffects"] = R.array.tile_states_desktopeffects
}
/** Get the subtitle resource id of the given tile */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 973265c6c9b1..fd5861fed20c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -43,8 +43,8 @@ import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.satellite.SatelliteDialogUtils;
import com.android.systemui.animation.Expandable;
+import com.android.systemui.bluetooth.qsdialog.BluetoothDetailsContentViewModel;
import com.android.systemui.bluetooth.qsdialog.BluetoothDetailsViewModel;
-import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogViewModel;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
@@ -84,7 +84,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
private final Executor mExecutor;
- private final BluetoothTileDialogViewModel mDialogViewModel;
+ private final BluetoothDetailsContentViewModel mDetailsContentViewModel;
private final FeatureFlags mFeatureFlags;
@Nullable
@@ -104,7 +104,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
QSLogger qsLogger,
BluetoothController bluetoothController,
FeatureFlags featureFlags,
- BluetoothTileDialogViewModel dialogViewModel
+ BluetoothDetailsContentViewModel detailsContentViewModel
) {
super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
@@ -112,7 +112,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
mController.observe(getLifecycle(), mCallback);
mExecutor = new HandlerExecutor(mainHandler);
mFeatureFlags = featureFlags;
- mDialogViewModel = dialogViewModel;
+ mDetailsContentViewModel = detailsContentViewModel;
}
@Override
@@ -133,7 +133,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
callback.accept(new BluetoothDetailsViewModel(() -> {
longClick(null);
return null;
- }, mDialogViewModel))
+ }, mDetailsContentViewModel))
);
return true;
}
@@ -158,7 +158,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
private void handleClickEvent(@Nullable Expandable expandable) {
if (mFeatureFlags.isEnabled(Flags.BLUETOOTH_QS_TILE_DIALOG)) {
- mDialogViewModel.showDetailsContent(expandable, /* view= */ null);
+ mDetailsContentViewModel.showDetailsContent(expandable, /* view= */ null);
} else {
// Secondary clicks are header clicks, just toggle.
toggleBluetooth();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
index 4d0e80854853..f80b8fb8cb1f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
@@ -36,7 +36,6 @@ import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel
import com.android.systemui.qs.tiles.dialog.InternetDialogManager
-import com.android.systemui.qs.tiles.dialog.WifiStateWorker
import com.android.systemui.res.R
import com.android.systemui.statusbar.connectivity.AccessPointController
import com.android.systemui.statusbar.pipeline.shared.ui.binder.InternetTileBinder
@@ -58,7 +57,6 @@ constructor(
qsLogger: QSLogger,
viewModel: InternetTileViewModel,
private val internetDialogManager: InternetDialogManager,
- private val wifiStateWorker: WifiStateWorker,
private val accessPointController: AccessPointController,
private val internetDetailsViewModelFactory: InternetDetailsViewModel.Factory,
) :
@@ -86,10 +84,7 @@ constructor(
mContext.getString(R.string.quick_settings_internet_label)
override fun newTileState(): QSTile.BooleanState {
- return QSTile.BooleanState().also {
- it.forceExpandIcon = true
- it.handlesSecondaryClick = true
- }
+ return QSTile.BooleanState().also { it.forceExpandIcon = true }
}
override fun handleClick(expandable: Expandable?) {
@@ -107,12 +102,6 @@ constructor(
return internetDetailsViewModelFactory.create { longClick(null) }
}
- override fun handleSecondaryClick(expandable: Expandable?) {
- // TODO(b/358352265): Figure out the correct action for the secondary click
- // Toggle wifi
- wifiStateWorker.isWifiEnabled = !wifiStateWorker.isWifiEnabled
- }
-
override fun handleUpdateState(state: QSTile.BooleanState, arg: Any?) {
state.label = mContext.resources.getString(R.string.quick_settings_internet_label)
state.expandedAccessibilityClassName = Button::class.java.name
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 42b35c736d42..7b88d6930279 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -26,6 +26,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
import android.widget.Switch;
+import android.widget.Toast;
import androidx.annotation.Nullable;
@@ -192,8 +193,19 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
@Override
public boolean getDetailsViewModel(Consumer<TileDetailsViewModel> callback) {
handleClick(() -> executeWhenUnlockedKeyguard(
- () -> callback.accept(new ScreenRecordDetailsViewModel(mController,
- this::onStartRecordingClicked)))
+ () -> {
+ if (mController.isScreenCaptureDisabled()) {
+ // Close the panel first so that the toast can show up.
+ mDialogTransitionAnimator.disableAllCurrentDialogsExitAnimations();
+ mPanelInteractor.collapsePanels();
+
+ showDisabledByPolicyToast();
+ return;
+ }
+
+ callback.accept(new ScreenRecordDetailsViewModel(mController,
+ this::onStartRecordingClicked));
+ })
);
return true;
}
@@ -244,6 +256,12 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
return mContext.getString(R.string.quick_settings_screen_record_label);
}
+ void showDisabledByPolicyToast() {
+ Toast.makeText(mContext,
+ R.string.screen_capturing_disabled_by_policy_dialog_description, Toast.LENGTH_SHORT)
+ .show();
+ }
+
private void cancelCountdown() {
Log.d(TAG, "Cancelling countdown");
mController.cancelCountdown();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacy.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacy.java
index c6bcab48fa68..75cb8ddca484 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacy.java
@@ -589,8 +589,10 @@ public class InternetDialogDelegateLegacy implements
}
mSecondaryMobileNetworkLayout = mDialogView.findViewById(
R.id.secondary_mobile_network_layout);
- mSecondaryMobileNetworkLayout.setOnClickListener(
- this::onClickConnectedSecondarySub);
+ if (mCanConfigMobileData) {
+ mSecondaryMobileNetworkLayout.setOnClickListener(
+ this::onClickConnectedSecondarySub);
+ }
mSecondaryMobileNetworkLayout.setBackground(mBackgroundOn);
TextView mSecondaryMobileTitleText = mDialogView.requireViewById(
@@ -623,6 +625,8 @@ public class InternetDialogDelegateLegacy implements
mDialogView.requireViewById(R.id.secondary_settings_icon);
mSecondaryMobileSettingsIcon.setColorFilter(
dialog.getContext().getColor(R.color.connected_network_primary_color));
+ mSecondaryMobileSettingsIcon.setVisibility(mCanConfigMobileData ?
+ View.VISIBLE : View.INVISIBLE);
// set secondary visual for default data sub
mMobileNetworkLayout.setBackground(mBackgroundOff);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsContent.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsContent.kt
index bf1a51d8cd59..3eb73d83bc1a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsContent.kt
@@ -28,13 +28,6 @@ import com.android.systemui.screenrecord.ScreenRecordPermissionViewBinder
@Composable
fun ScreenRecordDetailsContent(viewModel: ScreenRecordDetailsViewModel) {
- // TODO(b/378514312): Finish implementing this function.
-
- if (viewModel.recordingController.isScreenCaptureDisabled) {
- // TODO(b/388345506): Show disabled page here.
- return
- }
-
val viewBinder: ScreenRecordPermissionViewBinder = remember {
viewModel.recordingController.createScreenRecordPermissionViewBinder(
viewModel.onStartRecordingClicked
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt
index 7ad01e463399..8d5880554277 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt
@@ -92,10 +92,6 @@ constructor(
else QSTileState.ActivationState.INACTIVE
supportedActions =
- setOf(
- QSTileState.UserAction.CLICK,
- QSTileState.UserAction.TOGGLE_CLICK,
- QSTileState.UserAction.LONG_CLICK,
- )
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt
index 6e2c437b9c16..8e48fe492e13 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt
@@ -26,7 +26,6 @@ import com.android.systemui.qs.tiles.base.interactor.QSTileInput
import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel
import com.android.systemui.qs.tiles.dialog.InternetDialogManager
-import com.android.systemui.qs.tiles.dialog.WifiStateWorker
import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
import com.android.systemui.statusbar.connectivity.AccessPointController
@@ -40,7 +39,6 @@ class InternetTileUserActionInteractor
constructor(
@Main private val mainContext: CoroutineContext,
private val internetDialogManager: InternetDialogManager,
- private val wifiStateWorker: WifiStateWorker,
private val accessPointController: AccessPointController,
private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
private val internetDetailsViewModelFactory: InternetDetailsViewModel.Factory,
@@ -59,24 +57,17 @@ constructor(
)
}
}
- is QSTileUserAction.ToggleClick -> {
- // TODO(b/358352265): Figure out the correct action for the secondary click
- // Toggle Wifi
- wifiStateWorker.isWifiEnabled = !wifiStateWorker.isWifiEnabled
- }
is QSTileUserAction.LongClick -> {
handleLongClick(action.expandable)
}
+ else -> {}
}
}
override val detailsViewModel: TileDetailsViewModel =
internetDetailsViewModelFactory.create { handleLongClick(null) }
- private fun handleLongClick(expandable:Expandable?){
- qsTileIntentUserActionHandler.handle(
- expandable,
- Intent(Settings.ACTION_WIFI_SETTINGS)
- )
+ private fun handleLongClick(expandable: Expandable?) {
+ qsTileIntentUserActionHandler.handle(expandable, Intent(Settings.ACTION_WIFI_SETTINGS))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index caa7bbae0420..e357f63479dc 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -163,4 +163,12 @@ constructor(
fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
_transitionState.value = transitionState
}
+
+ /**
+ * If currently in a transition between contents, cancel that transition and go back to the
+ * pre-transition state.
+ */
+ fun freezeAndAnimateToCurrentState() {
+ dataSource.freezeAndAnimateToCurrentState()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 475c0794861f..01180859b1d2 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.scene.domain.interactor
+import com.android.app.tracing.coroutines.flow.stateInTraced
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.OverlayKey
@@ -52,7 +53,6 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
@@ -124,7 +124,8 @@ constructor(
val transitionState: StateFlow<ObservableTransitionState> =
repository.transitionState
.onEach { logger.logSceneTransition(it) }
- .stateIn(
+ .stateInTraced(
+ name = "transitionState",
scope = applicationScope,
started = SharingStarted.Eagerly,
initialValue = repository.transitionState.value,
@@ -145,7 +146,8 @@ constructor(
is ObservableTransitionState.Transition -> state.toContent
}
}
- .stateIn(
+ .stateInTraced(
+ name = "transitioningTo",
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue = null,
@@ -164,7 +166,8 @@ constructor(
is ObservableTransitionState.Idle -> flowOf(false)
}
}
- .stateIn(
+ .stateInTraced(
+ name = "isTransitionUserInputOngoing",
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue = false,
@@ -183,7 +186,8 @@ constructor(
activeTransitionAnimationCount = activeTransitionAnimationCount,
)
}
- .stateIn(
+ .stateInTraced(
+ name = "isVisible",
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue = isVisibleInternal(),
@@ -230,6 +234,10 @@ constructor(
* The change is animated. Therefore, it will be some time before the UI will switch to the
* desired scene. Once enough of the transition has occurred, the [currentScene] will become
* [toScene] (unless the transition is canceled by user action or another call to this method).
+ *
+ * If [forceSettleToTargetScene] is `true` and the target scene is the same as the current
+ * scene, any current transition will be canceled and an animation to the target scene will be
+ * started.
*/
@JvmOverloads
fun changeScene(
@@ -237,9 +245,19 @@ constructor(
loggingReason: String,
transitionKey: TransitionKey? = null,
sceneState: Any? = null,
+ forceSettleToTargetScene: Boolean = false,
) {
val currentSceneKey = currentScene.value
val resolvedScene = sceneFamilyResolvers.get()[toScene]?.resolvedScene?.value ?: toScene
+
+ if (resolvedScene == currentSceneKey && forceSettleToTargetScene) {
+ logger.logSceneChangeCancellation(scene = resolvedScene, sceneState = sceneState)
+ onSceneAboutToChangeListener.forEach {
+ it.onSceneAboutToChange(resolvedScene, sceneState)
+ }
+ repository.freezeAndAnimateToCurrentState()
+ }
+
if (
!validateSceneChange(
from = currentSceneKey,
@@ -519,14 +537,32 @@ constructor(
}
if (from == to) {
+ logger.logSceneChangeRejection(
+ from = from,
+ to = to,
+ originalChangeReason = loggingReason,
+ rejectionReason = "${from.debugName} is the same as ${to.debugName}",
+ )
return false
}
if (to !in repository.allContentKeys) {
+ logger.logSceneChangeRejection(
+ from = from,
+ to = to,
+ originalChangeReason = loggingReason,
+ rejectionReason = "${to.debugName} isn't present in allContentKeys",
+ )
return false
}
if (disabledContentInteractor.isDisabled(to)) {
+ logger.logSceneChangeRejection(
+ from = from,
+ to = to,
+ originalChangeReason = loggingReason,
+ rejectionReason = "${to.debugName} is currently disabled",
+ )
return false
}
@@ -576,14 +612,58 @@ constructor(
}
if (to != null && disabledContentInteractor.isDisabled(to)) {
+ logger.logSceneChangeRejection(
+ from = from,
+ to = to,
+ originalChangeReason = loggingReason,
+ rejectionReason = "${to.debugName} is currently disabled",
+ )
return false
}
- val isFromValid = (from == null) || (from in currentOverlays.value)
- val isToValid =
- (to == null) || (to !in currentOverlays.value && to in repository.allContentKeys)
+ return when {
+ to != null && from != null && to == from -> {
+ logger.logSceneChangeRejection(
+ from = from,
+ to = to,
+ originalChangeReason = loggingReason,
+ rejectionReason = "${from.debugName} is the same as ${to.debugName}",
+ )
+ false
+ }
- return isFromValid && isToValid && from != to
+ to != null && to !in repository.allContentKeys -> {
+ logger.logSceneChangeRejection(
+ from = from,
+ to = to,
+ originalChangeReason = loggingReason,
+ rejectionReason = "${to.debugName} is not in allContentKeys",
+ )
+ false
+ }
+
+ from != null && from !in currentOverlays.value -> {
+ logger.logSceneChangeRejection(
+ from = from,
+ to = to,
+ originalChangeReason = loggingReason,
+ rejectionReason = "${from.debugName} is not a current overlay",
+ )
+ false
+ }
+
+ to != null && to in currentOverlays.value -> {
+ logger.logSceneChangeRejection(
+ from = from,
+ to = to,
+ originalChangeReason = loggingReason,
+ rejectionReason = "${to.debugName} is already a current overlay",
+ )
+ false
+ }
+
+ else -> true
+ }
}
/** Returns a flow indicating if the currently visible scene can be resolved from [family]. */
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
index 140b231593bd..aab37d433e4f 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
@@ -16,7 +16,6 @@
package com.android.systemui.scene.domain.resolver
-import android.util.Log
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -84,7 +83,7 @@ constructor(
isDreamingWithOverlay: Boolean,
isAbleToDream: Boolean,
): SceneKey {
- val result = when {
+ return when {
// Dream can run even if Keyguard is disabled, thus it has the highest priority here.
isDreamingWithOverlay && isAbleToDream -> Scenes.Dream
!isKeyguardEnabled -> Scenes.Gone
@@ -93,21 +92,9 @@ constructor(
!isUnlocked -> Scenes.Lockscreen
else -> Scenes.Gone
}
- Log.d(TAG, "homeScene emitting $result, values:")
- Log.d(TAG, " isKeyguardEnabled=$isKeyguardEnabled")
- Log.d(TAG, " canSwipeToEnter=$canSwipeToEnter")
- Log.d(TAG, " isDeviceEntered=$isDeviceEntered" )
- Log.d(TAG, " isUnlocked=$isUnlocked")
- Log.d(TAG, " isDreamingWithOverlay=$isDreamingWithOverlay")
- Log.d(TAG, " isAbleToDream=$isAbleToDream")
- Log.d(TAG, "")
- return result
}
companion object {
-
- private const val TAG = "HomeSceneFamilyResolver"
-
val homeScenes =
setOf(
Scenes.Gone,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 94e32fcb9ac6..218ad477c45e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -90,6 +90,7 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
@@ -553,6 +554,7 @@ constructor(
targetSceneKey = Scenes.Lockscreen,
loggingReason = "device is starting to sleep",
sceneState = keyguardInteractor.asleepKeyguardState.value,
+ freezeAndAnimateToCurrentState = true,
)
} else {
val canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value
@@ -610,15 +612,24 @@ constructor(
private fun handleShadeTouchability() {
applicationScope.launch {
- shadeInteractor.isShadeTouchable
- .distinctUntilChanged()
- .filter { !it }
- .collect {
- switchToScene(
- targetSceneKey = Scenes.Lockscreen,
- loggingReason = "device became non-interactive (SceneContainerStartable)",
- )
+ repeatWhen(deviceEntryInteractor.isDeviceEntered.map { !it }) {
+ // Run logic only when the device isn't entered.
+ repeatWhen(
+ sceneInteractor.transitionState.map { !it.isTransitioning(to = Scenes.Gone) }
+ ) {
+ // Run logic only when not transitioning to gone.
+ shadeInteractor.isShadeTouchable
+ .distinctUntilChanged()
+ .filter { !it }
+ .collect {
+ switchToScene(
+ targetSceneKey = Scenes.Lockscreen,
+ loggingReason =
+ "device became non-interactive (SceneContainerStartable)",
+ )
+ }
}
+ }
}
}
@@ -923,11 +934,13 @@ constructor(
targetSceneKey: SceneKey,
loggingReason: String,
sceneState: Any? = null,
+ freezeAndAnimateToCurrentState: Boolean = false,
) {
sceneInteractor.changeScene(
toScene = targetSceneKey,
loggingReason = loggingReason,
sceneState = sceneState,
+ forceSettleToTargetScene = freezeAndAnimateToCurrentState,
)
}
@@ -1013,6 +1026,14 @@ constructor(
}
}
+ private suspend fun repeatWhen(condition: Flow<Boolean>, block: suspend () -> Unit) {
+ condition.distinctUntilChanged().collectLatest { conditionMet ->
+ if (conditionMet) {
+ block()
+ }
+ }
+ }
+
companion object {
private const val TAG = "SceneContainerStartable"
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
index d00585858ccb..73c71f6088e1 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
@@ -16,6 +16,7 @@
package com.android.systemui.scene.shared.logger
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
@@ -74,6 +75,50 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
)
}
+ fun logSceneChangeCancellation(scene: SceneKey, sceneState: Any?) {
+ logBuffer.log(
+ tag = TAG,
+ level = LogLevel.INFO,
+ messageInitializer = {
+ str1 = scene.debugName
+ str2 = sceneState?.toString()
+ },
+ messagePrinter = { "CANCELED scene change. scene: $str1, sceneState: $str2" },
+ )
+ }
+
+ fun logSceneChangeRejection(
+ from: ContentKey?,
+ to: ContentKey?,
+ originalChangeReason: String,
+ rejectionReason: String,
+ ) {
+ logBuffer.log(
+ tag = TAG,
+ level = LogLevel.INFO,
+ messageInitializer = {
+ str1 = "${from?.debugName ?: "<none>"} → ${to?.debugName ?: "<none>"}"
+ str2 = rejectionReason
+ str3 = originalChangeReason
+ bool1 = to is OverlayKey
+ },
+ messagePrinter = {
+ buildString {
+ append("REJECTED ")
+ append(
+ if (bool1) {
+ "overlay "
+ } else {
+ "scene "
+ }
+ )
+ append("change $str1 because \"$str2\" ")
+ append("(original change reason: \"$str3\")")
+ }
+ },
+ )
+ }
+
fun logSceneTransition(transitionState: ObservableTransitionState) {
when (transitionState) {
is ObservableTransitionState.Transition -> {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt
index daf2d7f698b6..42c4b24a72d3 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt
@@ -83,4 +83,10 @@ interface SceneDataSource {
/** Asks for [overlay] to be instantly hidden, without an animated transition of any kind. */
fun instantlyHideOverlay(overlay: OverlayKey)
+
+ /**
+ * If currently in a transition between contents, cancel that transition and go back to the
+ * pre-transition state.
+ */
+ fun freezeAndAnimateToCurrentState()
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
index dcb699539760..d6dce38d0bbf 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
@@ -82,6 +82,10 @@ class SceneDataSourceDelegator(applicationScope: CoroutineScope, config: SceneCo
delegateMutable.value.instantlyHideOverlay(overlay)
}
+ override fun freezeAndAnimateToCurrentState() {
+ delegateMutable.value.freezeAndAnimateToCurrentState()
+ }
+
/**
* Binds the current, dependency injection provided [SceneDataSource] to the given object.
*
@@ -120,5 +124,7 @@ class SceneDataSourceDelegator(applicationScope: CoroutineScope, config: SceneCo
override fun instantlyShowOverlay(overlay: OverlayKey) = Unit
override fun instantlyHideOverlay(overlay: OverlayKey) = Unit
+
+ override fun freezeAndAnimateToCurrentState() = Unit
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTileSet.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTileSet.java
index 76a72f7e4adf..25c38050e95a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTileSet.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/ImageTileSet.java
@@ -29,6 +29,7 @@ import androidx.annotation.UiThread;
import com.android.internal.util.CallbackRegistry;
import com.android.internal.util.CallbackRegistry.NotifierCallback;
+import com.android.systemui.dagger.qualifiers.Main;
import java.util.ArrayList;
import java.util.Iterator;
@@ -49,7 +50,7 @@ class ImageTileSet {
private CallbackRegistry<OnContentChangedListener, ImageTileSet, Rect> mContentListeners;
@Inject
- ImageTileSet(@UiThread Handler handler) {
+ ImageTileSet(@Main Handler handler) {
mHandler = handler;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/BaseShadeControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/BaseShadeControllerImpl.kt
index b271c6979b31..71977ef1f234 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/BaseShadeControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/BaseShadeControllerImpl.kt
@@ -16,19 +16,19 @@
package com.android.systemui.shade
+import com.android.keyguard.KeyguardViewController
import com.android.systemui.assist.AssistManager
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.NotificationShadeWindowController
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import dagger.Lazy
/** A base class for non-empty implementations of ShadeController. */
abstract class BaseShadeControllerImpl(
protected val commandQueue: CommandQueue,
- protected val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+ protected val keyguardViewController: KeyguardViewController,
protected val notificationShadeWindowController: NotificationShadeWindowController,
- protected val assistManagerLazy: Lazy<AssistManager>
+ protected val assistManagerLazy: Lazy<AssistManager>,
) : ShadeController {
protected lateinit var notifPresenter: NotificationPresenter
/** Runnables to run after completing a collapse of the shade. */
@@ -66,7 +66,7 @@ abstract class BaseShadeControllerImpl(
for (r in clonedList) {
r.run()
}
- statusBarKeyguardViewManager.readyForKeyguardDone()
+ keyguardViewController.readyForKeyguardDone()
}
final override fun onLaunchAnimationEnd(launchIsFullScreen: Boolean) {
@@ -77,6 +77,7 @@ abstract class BaseShadeControllerImpl(
instantCollapseShade()
}
}
+
final override fun onLaunchAnimationCancelled(isLaunchForActivity: Boolean) {
if (
notifPresenter.isPresenterFullyCollapsed() &&
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 305e71e48702..3be2f1b7b957 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -231,6 +231,9 @@ constructor(
*/
private var isDreaming = false
+ /** True if we should allow swiping open the glanceable hub. */
+ private var swipeToHubEnabled = false
+
/** Observes and logs state when the lifecycle that controls the [touchMonitor] updates. */
private val touchLifecycleLogger: LifecycleObserver = LifecycleEventObserver { _, event ->
logger.d({
@@ -438,6 +441,7 @@ constructor(
},
)
collectFlow(containerView, keyguardInteractor.isDreaming, { isDreaming = it })
+ collectFlow(containerView, communalViewModel.swipeToHubEnabled, { swipeToHubEnabled = it })
communalContainerWrapper = CommunalWrapper(containerView.context)
communalContainerWrapper?.addView(communalContainerView)
@@ -520,10 +524,7 @@ constructor(
val glanceableHubV2 = communalSettingsInteractor.isV2FlagEnabled()
if (
!hubShowing &&
- (touchOnNotifications ||
- touchOnUmo ||
- touchOnSmartspace ||
- !communalViewModel.swipeToHubEnabled())
+ (touchOnNotifications || touchOnUmo || touchOnSmartspace || !swipeToHubEnabled)
) {
logger.d({
"Lockscreen touch ignored: touchOnNotifications: $bool1, touchOnUmo: $bool2, " +
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index 0e30f2b4bb30..acae1bc81b97 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -23,6 +23,7 @@ import android.view.MotionEvent;
import android.view.ViewTreeObserver;
import android.view.WindowManagerGlobal;
+import com.android.keyguard.KeyguardViewController;
import com.android.systemui.DejankUtils;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dagger.SysUISingleton;
@@ -35,7 +36,6 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
@@ -61,7 +61,6 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl {
private final KeyguardStateController mKeyguardStateController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final StatusBarStateController mStatusBarStateController;
- private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final StatusBarWindowControllerStore mStatusBarWindowControllerStore;
private final DeviceProvisionedController mDeviceProvisionedController;
@@ -82,7 +81,7 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl {
WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ KeyguardViewController keyguardViewController,
StatusBarWindowControllerStore statusBarWindowControllerStore,
DeviceProvisionedController deviceProvisionedController,
NotificationShadeWindowController notificationShadeWindowController,
@@ -93,7 +92,7 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl {
Lazy<NotificationGutsManager> gutsManager
) {
super(commandQueue,
- statusBarKeyguardViewManager,
+ keyguardViewController,
notificationShadeWindowController,
assistManagerLazy);
SceneContainerFlag.assertInLegacyMode();
@@ -107,7 +106,6 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl {
mGutsManager = gutsManager;
mNotificationShadeWindowController = notificationShadeWindowController;
mNotifShadeWindowViewController = notificationShadeWindowViewController;
- mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mDisplayId = displayId;
mKeyguardStateController = keyguardStateController;
mAssistManagerLazy = assistManagerLazy;
@@ -396,7 +394,7 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl {
@Override
public void collapseShadeForActivityStart() {
- if (isExpandedVisible() && !mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ if (isExpandedVisible() && !getKeyguardViewController().isBouncerShowing()) {
animateCollapseShadeForcedDelayed();
} else {
// Do it after DismissAction has been processed to conserve the
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index f926d39760fe..96b224fbd4f3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -42,12 +42,12 @@ import com.android.systemui.shade.display.ShadeDisplayPolicyModule
import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor
import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractorImpl
import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor
-import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
+import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHider
+import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHiderImpl
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
import com.android.systemui.statusbar.phone.ConfigurationForwarder
import com.android.systemui.statusbar.policy.ConfigurationController
-import dagger.BindsOptionalOf
import dagger.Module
import dagger.Provides
import dagger.multibindings.ClassKey
@@ -67,7 +67,7 @@ import javax.inject.Qualifier
* By using this dedicated module, we ensure the notification shade window always utilizes the
* correct display context and resources, regardless of the display it's on.
*/
-@Module(includes = [OptionalShadeDisplayAwareBindings::class, ShadeDisplayPolicyModule::class])
+@Module(includes = [ShadeDisplayPolicyModule::class])
object ShadeDisplayAwareModule {
/** Creates a new context for the shade window. */
@@ -242,17 +242,6 @@ object ShadeDisplayAwareModule {
}
}
- @Provides
- @IntoMap
- @ClassKey(ShadeDisplaysInteractor::class)
- fun provideShadeDisplaysInteractor(impl: Provider<ShadeDisplaysInteractor>): CoreStartable {
- return if (ShadeWindowGoesAround.isEnabled) {
- impl.get()
- } else {
- CoreStartable.NOP
- }
- }
-
/**
* Provided for making classes easier to test. In tests, a custom method to wait for the next
* frame can be easily provided.
@@ -264,11 +253,25 @@ object ShadeDisplayAwareModule {
fun provideShadeOnDefaultDisplayWhenLocked(): Boolean = true
}
+/** Module that should be included only if the shade window [WindowRootView] is available. */
@Module
-internal interface OptionalShadeDisplayAwareBindings {
- @BindsOptionalOf fun bindOptionalOfWindowRootView(): WindowRootView
+object ShadeDisplayAwareWithShadeWindowModule {
+ @Provides
+ @IntoMap
+ @ClassKey(ShadeDisplaysInteractor::class)
+ fun provideShadeDisplaysInteractor(impl: Provider<ShadeDisplaysInteractor>): CoreStartable {
+ return if (ShadeWindowGoesAround.isEnabled) {
+ impl.get()
+ } else {
+ CoreStartable.NOP
+ }
+ }
- @BindsOptionalOf fun bindOptionalOShadeExpandedStateInteractor(): ShadeExpandedStateInteractor
+ @Provides
+ @SysUISingleton
+ fun bindNotificationStackRebindingHider(
+ impl: NotificationStackRebindingHiderImpl
+ ): NotificationStackRebindingHider = impl
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt
index 13b540aa54ba..5fda998dac2d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt
@@ -24,8 +24,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
-import com.android.systemui.util.kotlin.getOrNull
-import java.util.Optional
import java.util.concurrent.CancellationException
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
@@ -51,22 +49,13 @@ import kotlinx.coroutines.withTimeout
class ShadeDisplayChangeLatencyTracker
@Inject
constructor(
- optionalShadeRootView: Optional<WindowRootView>,
+ private val shadeRootView: WindowRootView,
@ShadeDisplayAware private val configurationRepository: ConfigurationRepository,
private val latencyTracker: LatencyTracker,
@Background private val bgScope: CoroutineScope,
private val choreographerUtils: ChoreographerUtils,
) {
- private val shadeRootView =
- optionalShadeRootView.getOrNull()
- ?: error(
- """
- ShadeRootView must be provided for ShadeDisplayChangeLatencyTracker to work.
- If it is not, it means this is being instantiated in a SystemUI variant that shouldn't.
- """
- .trimIndent()
- )
/**
* We need to keep this always up to date eagerly to avoid delays receiving the new display ID.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 7d4b0ed6304c..c44e066aad3a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -54,7 +54,12 @@ import javax.inject.Provider
/** Module for classes related to the notification shade. */
@Module(
includes =
- [StartShadeModule::class, ShadeViewProviderModule::class, WindowRootViewBlurModule::class]
+ [
+ StartShadeModule::class,
+ ShadeViewProviderModule::class,
+ WindowRootViewBlurModule::class,
+ ShadeDisplayAwareWithShadeWindowModule::class,
+ ]
)
abstract class ShadeModule {
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
index e746274a39c1..9a5c96824e77 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
@@ -39,9 +39,7 @@ import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotif
import com.android.systemui.statusbar.notification.row.NotificationRebindingTracker
import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHider
import com.android.systemui.statusbar.phone.ConfigurationForwarder
-import com.android.systemui.util.kotlin.getOrNull
import com.android.window.flags.Flags
-import java.util.Optional
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlin.time.Duration.Companion.seconds
@@ -63,17 +61,14 @@ constructor(
@Background private val bgScope: CoroutineScope,
@Main private val mainThreadContext: CoroutineContext,
private val shadeDisplayChangeLatencyTracker: ShadeDisplayChangeLatencyTracker,
- shadeExpandedInteractor: Optional<ShadeExpandedStateInteractor>,
+ private val shadeExpandedInteractor: ShadeExpandedStateInteractor,
private val shadeExpansionIntent: ShadeExpansionIntent,
private val activeNotificationsInteractor: ActiveNotificationsInteractor,
private val notificationRebindingTracker: NotificationRebindingTracker,
- notificationStackRebindingHider: Optional<NotificationStackRebindingHider>,
+ private val notificationStackRebindingHider: NotificationStackRebindingHider,
@ShadeDisplayAware private val configForwarder: ConfigurationForwarder,
) : CoreStartable {
- private val shadeExpandedInteractor = requireOptional(shadeExpandedInteractor)
- private val notificationStackRebindingHider = requireOptional(notificationStackRebindingHider)
-
private val hasActiveNotifications: Boolean
get() = activeNotificationsInteractor.areAnyNotificationsPresentValue
@@ -224,24 +219,5 @@ constructor(
const val TAG = "ShadeDisplaysInteractor"
const val COLLAPSE_EXPAND_REASON = "Shade window move"
val TIMEOUT = 1.seconds
-
- /**
- * [ShadeDisplaysInteractor] is bound in the SystemUI module for all variants, but needs
- * some specific dependencies to be bound from each variant (e.g.
- * [ShadeExpandedStateInteractor] or [NotificationStackRebindingHider]). When those are not
- * bound, this class is not expected to be instantiated, and trying to instantiate it would
- * crash.
- */
- inline fun <reified T> requireOptional(optional: Optional<T>): T {
- return optional.getOrNull()
- ?: error(
- """
- ${T::class.java.simpleName} must be provided for ShadeDisplaysInteractor to work.
- If it is not, it means this is being instantiated in a SystemUI variant that
- shouldn't.
- """
- .trimIndent()
- )
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 9d81be2091c2..e8b5d5bdf7df 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -16,7 +16,6 @@
package com.android.systemui.shade.domain.interactor
-import android.util.Log
import com.android.app.tracing.coroutines.flow.flowName
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -39,7 +38,6 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
/** The non-empty [ShadeInteractor] implementation. */
@@ -100,31 +98,17 @@ constructor(
override val isShadeTouchable: Flow<Boolean> =
combine(
- powerInteractor.isAsleep.onEach {
- Log.d(TAG, "isShadeTouchable: upstream isAsleep=$it")
- },
- keyguardTransitionInteractor
- .isInTransition(Edge.create(to = KeyguardState.AOD))
- .onEach { Log.d(TAG, "isShadeTouchable: upstream isTransitioningToAod=$it") },
- keyguardRepository.dozeTransitionModel
- .map { it.to == DozeStateModel.DOZE_PULSING }
- .onEach { Log.d(TAG, "isShadeTouchable: upstream isPulsing=$it") },
+ powerInteractor.isAsleep,
+ keyguardTransitionInteractor.isInTransition(Edge.create(to = KeyguardState.AOD)),
+ keyguardRepository.dozeTransitionModel.map { it.to == DozeStateModel.DOZE_PULSING },
) { isAsleep, isTransitioningToAod, isPulsing ->
- val downstream =
- when {
- // If the device is transitioning to AOD, only accept touches if
- // still animating.
- isTransitioningToAod -> dozeParams.shouldControlScreenOff()
- // If the device is asleep, only accept touches if there's a pulse
- isAsleep -> isPulsing
- else -> true
- }
- Log.d(TAG, "isShadeTouchable emitting $downstream, values:")
- Log.d(TAG, " isAsleep=$isAsleep")
- Log.d(TAG, " isTransitioningToAod=$isTransitioningToAod")
- Log.d(TAG, " isPulsing=$isPulsing")
- Log.d(TAG, "")
- downstream
+ when {
+ // If the device is transitioning to AOD, only accept touches if still animating.
+ isTransitioningToAod -> dozeParams.shouldControlScreenOff()
+ // If the device is asleep, only accept touches if there's a pulse
+ isAsleep -> isPulsing
+ else -> true
+ }
}
override val isExpandToQsEnabled: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt b/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt
index c23ff5302b3c..dc444ffc2a34 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade.shared.flag
+import android.window.DesktopExperienceFlags
import com.android.systemui.Flags
import com.android.systemui.flags.FlagToken
import com.android.systemui.flags.RefactorFlagUtils
@@ -30,10 +31,26 @@ object ShadeWindowGoesAround {
val token: FlagToken
get() = FlagToken(FLAG_NAME, isEnabled)
+ /**
+ * This is defined as [DesktopExperienceFlags] to make it possible to enable it together with
+ * all the other desktop experience flags from the dev settings.
+ *
+ * Alternatively, using adb:
+ * ```bash
+ * adb shell aflags enable com.android.window.flags.show_desktop_experience_dev_option && \
+ * adb shell setprop persist.wm.debug.desktop_experience_devopts 1
+ * ```
+ */
+ val FLAG =
+ DesktopExperienceFlags.DesktopExperienceFlag(
+ Flags::shadeWindowGoesAround,
+ /* shouldOverrideByDevOption= */ true,
+ )
+
/** Is the refactor enabled */
@JvmStatic
inline val isEnabled: Boolean
- get() = Flags.shadeWindowGoesAround()
+ get() = FLAG.isTrue
/**
* Called to ensure code is only run when the flag is enabled. This protects users from the
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/ShadeColors.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/ShadeColors.kt
index 8db622566e5e..62428471f08b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/ShadeColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/ShadeColors.kt
@@ -23,18 +23,48 @@ import com.android.systemui.res.R
object ShadeColors {
@JvmStatic
- fun Resources.shadePanel(): Int {
- val layerAbove =
- ColorUtils.setAlphaComponent(getColor(R.color.shade_panel_base), (0.4f * 255).toInt())
+ fun Resources.shadePanel(blurSupported: Boolean): Int {
+ return if (blurSupported) {
+ shadePanelStandard()
+ } else {
+ shadePanelFallback()
+ }
+ }
+
+ @JvmStatic
+ fun Resources.notificationScrim(blurSupported: Boolean): Int {
+ return if (blurSupported) {
+ notificationScrimStandard()
+ } else {
+ notificationScrimFallback()
+ }
+ }
+
+ @JvmStatic
+ private fun Resources.shadePanelStandard(): Int {
+ val layerAbove = ColorUtils.setAlphaComponent(
+ getColor(R.color.shade_panel_base, null),
+ (0.4f * 255).toInt()
+ )
val layerBelow = ColorUtils.setAlphaComponent(Color.WHITE, (0.1f * 255).toInt())
return ColorUtils.compositeColors(layerAbove, layerBelow)
}
@JvmStatic
- fun Resources.notificationScrim(): Int {
+ private fun Resources.shadePanelFallback(): Int {
+ return getColor(R.color.shade_panel_fallback, null)
+ }
+
+ @JvmStatic
+ private fun Resources.notificationScrimStandard(): Int {
return ColorUtils.setAlphaComponent(
- getColor(R.color.notification_scrim_base),
+ getColor(R.color.notification_scrim_base, null),
(0.5f * 255).toInt(),
)
}
+
+ @JvmStatic
+ private fun Resources.notificationScrimFallback(): Int {
+ return getColor(R.color.notification_scrim_fallback, null)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt
index a58ce4162ddc..02cec13d2ce8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt
@@ -26,6 +26,7 @@ import com.android.settingslib.flags.Flags.newStatusBarIcons
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.unified.BatteryColors
import com.android.systemui.res.R
+import com.android.systemui.statusbar.core.NewStatusBarIcons
import com.android.systemui.statusbar.events.BackgroundAnimatableView
class BatteryStatusChip @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
@@ -37,6 +38,8 @@ class BatteryStatusChip @JvmOverloads constructor(context: Context, attrs: Attri
get() = batteryMeterView
init {
+ NewStatusBarIcons.assertInLegacyMode()
+
inflate(context, R.layout.battery_status_chip, this)
roundedContainer = requireViewById(R.id.rounded_container)
batteryMeterView = requireViewById(R.id.battery_meter_view)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 3e761079bc49..6aa2fe29e768 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -38,7 +38,6 @@ import com.android.systemui.Flags
import com.android.systemui.Flags.spatialModelAppPushback
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -61,8 +60,6 @@ import java.util.Optional
import javax.inject.Inject
import kotlin.math.max
import kotlin.math.sign
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
/**
* Responsible for blurring the notification shade window, and applying a zoom effect to the
@@ -84,7 +81,6 @@ constructor(
@ShadeDisplayAware private val context: Context,
private val splitShadeStateController: SplitShadeStateController,
private val windowRootViewBlurInteractor: WindowRootViewBlurInteractor,
- @Application private val applicationScope: CoroutineScope,
private val appZoomOutOptional: Optional<AppZoomOut>,
dumpManager: DumpManager,
configurationController: ConfigurationController,
@@ -394,18 +390,15 @@ constructor(
private fun initBlurListeners() {
if (!Flags.bouncerUiRevamp()) return
- applicationScope.launch {
- Log.d(TAG, "Starting coroutines for window root view blur")
- windowRootViewBlurInteractor.onBlurAppliedEvent.collect { appliedBlurRadius ->
- if (updateScheduled) {
- // Process the blur applied event only if we scheduled the update
- TrackTracer.instantForGroup("shade", "shade_blur_radius", appliedBlurRadius)
- updateScheduled = false
- onBlurApplied(appliedBlurRadius, zoomOutCalculatedFromShadeRadius)
- } else {
- // Try scheduling an update now, maybe our blur request will be scheduled now.
- scheduleUpdate()
- }
+ windowRootViewBlurInteractor.registerBlurAppliedListener { appliedBlurRadius ->
+ if (updateScheduled) {
+ // Process the blur applied event only if we scheduled the update
+ TrackTracer.instantForGroup("shade", "shade_blur_radius", appliedBlurRadius)
+ updateScheduled = false
+ onBlurApplied(appliedBlurRadius, zoomOutCalculatedFromShadeRadius)
+ } else {
+ // Try scheduling an update now, maybe our blur request will be scheduled now.
+ scheduleUpdate()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
index a9338885d4c2..d8c3e2546a8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.chips.notification.domain.interactor
+import com.android.systemui.activity.data.model.AppVisibilityModel
import com.android.systemui.activity.data.repository.ActivityManagerRepository
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
@@ -30,8 +31,6 @@ import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.map
/**
* Interactor representing a single notification's status bar chip.
@@ -53,6 +52,7 @@ constructor(
@StatusBarChipsLog private val logBuffer: LogBuffer,
) {
private val key = startingModel.key
+ private val uid = startingModel.uid
private val logger = Logger(logBuffer, "Notif".pad())
// [StatusBarChipLogTag] recommends a max tag length of 20, so [extraLogTag] should NOT be the
// top-level tag. It should instead be provided as the first string in each log message.
@@ -88,34 +88,37 @@ constructor(
}
return
}
+
+ if (model.uid != uid) {
+ logger.e({
+ "$str1: received model with different uid, which shouldn't happen. " +
+ "Original UID: $int1, New UID: $int2. " +
+ "Proceeding as usual, but app visibility changes will be for *old* UID."
+ }) {
+ str1 = extraLogTag
+ int1 = uid
+ int2 = model.uid
+ }
+ }
_notificationModel.value = model
}
- private val uid: Flow<Int> = _notificationModel.map { it.uid }
-
- /** True if the application managing the notification is visible to the user. */
- private val isAppVisible: Flow<Boolean> =
- uid.flatMapLatest { currentUid ->
- activityManagerRepository.createIsAppVisibleFlow(currentUid, logger, extraLogTag)
- }
+ /** Details about when the app managing the notification was & is visible to the user. */
+ private val appVisibility: Flow<AppVisibilityModel> =
+ activityManagerRepository.createAppVisibilityFlow(uid, logger, extraLogTag)
/**
* Emits this notification's status bar chip, or null if this notification shouldn't show a
* status bar chip.
*/
val notificationChip: Flow<NotificationChipModel?> =
- combine(_notificationModel, isAppVisible) { notif, isAppVisible ->
- if (isAppVisible) {
- // If the app that posted this notification is visible, we want to hide the chip
- // because information between the status bar chip and the app itself could be
- // out-of-sync (like a timer that's slightly off)
- null
- } else {
- notif.toNotificationChipModel()
- }
+ combine(_notificationModel, appVisibility) { notif, appVisibility ->
+ notif.toNotificationChipModel(appVisibility)
}
- private fun ActiveNotificationModel.toNotificationChipModel(): NotificationChipModel? {
+ private fun ActiveNotificationModel.toNotificationChipModel(
+ appVisibility: AppVisibilityModel
+ ): NotificationChipModel? {
val promotedContent = this.promotedContent
if (promotedContent == null) {
logger.w({
@@ -138,7 +141,15 @@ constructor(
}
}
- return NotificationChipModel(key, appName, statusBarChipIconView, promotedContent)
+ return NotificationChipModel(
+ key = key,
+ appName = appName,
+ statusBarChipIconView = statusBarChipIconView,
+ promotedContent = promotedContent,
+ creationTime = creationTime,
+ isAppVisible = appVisibility.isAppCurrentlyVisible,
+ lastAppVisibleTime = appVisibility.lastAppVisibleTime,
+ )
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
index 9463db57585b..edb44185459c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
@@ -32,6 +32,7 @@ import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotif
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
+import kotlin.math.max
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -39,9 +40,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
/** An interactor for the notification chips shown in the status bar. */
@SysUISingleton
@@ -132,9 +135,6 @@ constructor(
}
interactor.setNotification(notif)
}
- logger.d({ "Interactors: $str1" }) {
- str1 = promotedNotificationInteractorMap.keys.joinToString(separator = " /// ")
- }
promotedNotificationInteractors.value =
promotedNotificationInteractorMap.values.toList()
}
@@ -142,29 +142,26 @@ constructor(
}
/**
- * A flow modeling the notifications that should be shown as chips in the status bar. Emits an
- * empty list if there are no notifications that should show a status bar chip.
+ * Emits all notifications that are eligible to show as chips in the status bar. This is
+ * different from which chips will *actually* show, see [shownNotificationChips] for that.
*/
- val notificationChips: Flow<List<NotificationChipModel>> =
+ val allNotificationChips: Flow<List<NotificationChipModel>> =
if (StatusBarNotifChips.isEnabled) {
// For all our current interactors...
- promotedNotificationInteractors.flatMapLatest { intrs ->
- // Stable-sort the promoted notifications by when they first appeared so that:
- // 1) The chips don't switch places if the older chip gets a notification update.
- // 2) The chips don't switch places when the second chip is tapped. (Whichever
- // notification is showing heads-up is considered to be the top notification, which
- // means tapping the second chip would move it to be the first chip if we didn't
- // sort by appearance time here.)
- // 3) Older chips get hidden if there's not enough room for all chips.
- val interactors = intrs.sortedByDescending { it.creationTime }
+ // TODO(b/364653005): When a promoted notification is added or removed, each individual
+ // interactor's [notificationChip] flow becomes un-collected then re-collected, which
+ // can cause some flows to remove then add callbacks when they don't need to. Is there a
+ // better structure for this? Maybe Channels or a StateFlow with a short timeout?
+ promotedNotificationInteractors.flatMapLatest { interactors ->
if (interactors.isNotEmpty()) {
// Combine each interactor's [notificationChip] flow...
val allNotificationChips: List<Flow<NotificationChipModel?>> =
interactors.map { interactor -> interactor.notificationChip }
combine(allNotificationChips) {
- // ... and emit just the non-null chips
- it.filterNotNull()
- }
+ // ... and emit just the non-null & sorted chips
+ it.filterNotNull().sortedWith(chipComparator)
+ }
+ .logSort()
} else {
flowOf(emptyList())
}
@@ -172,4 +169,44 @@ constructor(
} else {
flowOf(emptyList())
}
+
+ /** Emits the notifications that should actually be *shown* as chips in the status bar. */
+ val shownNotificationChips: Flow<List<NotificationChipModel>> =
+ allNotificationChips.map { chipsList ->
+ // If the app that posted this notification is visible, we want to hide the chip
+ // because information between the status bar chip and the app itself could be
+ // out-of-sync (like a timer that's slightly off)
+ chipsList.filter { !it.isAppVisible }
+ }
+
+ /*
+ Stable sort the promoted notifications by two criteria:
+ Criteria #1: Whichever app was most recently visible has higher ranking.
+ - Reasoning: If a user opened the app to see additional information, that's
+ likely the most important ongoing notification.
+ Criteria #2: Whichever notification first appeared more recently has higher ranking.
+ - Reasoning: Older chips get hidden if there's not enough room for all chips.
+ This semi-stable ordering ensures:
+ 1) The chips don't switch places if the older chip gets a notification update.
+ 2) The chips don't switch places when the second chip is tapped. (Whichever
+ notification is showing heads-up is considered to be the top notification, which
+ means tapping the second chip would move it to be the first chip if we didn't
+ sort by appearance time here.)
+ */
+ private val chipComparator =
+ compareByDescending<NotificationChipModel> {
+ max(it.creationTime, it.lastAppVisibleTime ?: Long.MIN_VALUE)
+ }
+
+ private fun Flow<List<NotificationChipModel>>.logSort(): Flow<List<NotificationChipModel>> {
+ return this.distinctUntilChanged().onEach { chips ->
+ val logString =
+ chips.joinToString {
+ "{key=${it.key}. " +
+ "lastVisibleAppTime=${it.lastAppVisibleTime}. " +
+ "creationTime=${it.creationTime}}"
+ }
+ logger.d({ "Sorted chips: $str1" }) { str1 = logString }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
index e7a90804a768..1f2079d83e6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
@@ -22,8 +22,17 @@ import com.android.systemui.statusbar.notification.promoted.shared.model.Promote
/** Modeling all the data needed to render a status bar notification chip. */
data class NotificationChipModel(
val key: String,
- /** The user-readable name of the app that posted the call notification. */
+ /** The user-readable name of the app that posted this notification. */
val appName: String,
val statusBarChipIconView: StatusBarIconView?,
val promotedContent: PromotedNotificationContentModel,
+ /** The time when the notification first appeared as promoted. */
+ val creationTime: Long,
+ /** True if the app managing this notification is currently visible to the user. */
+ val isAppVisible: Boolean,
+ /**
+ * The time when the app managing this notification last appeared as visible, or null if the app
+ * hasn't become visible since the notification became promoted.
+ */
+ val lastAppVisibleTime: Long?,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
index 2d6102e310f2..11e9fd56288f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.notification.domain.model.TopPinnedState
import com.android.systemui.statusbar.notification.headsup.PinnedStatus
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -51,6 +52,7 @@ constructor(
@Application private val applicationScope: CoroutineScope,
private val notifChipsInteractor: StatusBarNotificationChipsInteractor,
headsUpNotificationInteractor: HeadsUpNotificationInteractor,
+ private val systemClock: SystemClock,
) {
/**
* A flow modeling the notification chips that should be shown. Emits an empty list if there are
@@ -58,7 +60,7 @@ constructor(
*/
val chips: Flow<List<OngoingActivityChipModel.Active>> =
combine(
- notifChipsInteractor.notificationChips,
+ notifChipsInteractor.shownNotificationChips,
headsUpNotificationInteractor.statusBarHeadsUpState,
) { notifications, headsUpState ->
notifications.map { it.toActivityChipModel(headsUpState) }
@@ -158,16 +160,38 @@ constructor(
clickBehavior,
)
}
+
when (this.promotedContent.time.mode) {
PromotedNotificationContentModel.When.Mode.BasicTime -> {
- return OngoingActivityChipModel.Active.ShortTimeDelta(
- this.key,
- icon,
- colors,
- time = this.promotedContent.time.time,
- onClickListenerLegacy,
- clickBehavior,
- )
+ return if (
+ this.promotedContent.time.time >=
+ systemClock.currentTimeMillis() + FUTURE_TIME_THRESHOLD_MILLIS
+ ) {
+ OngoingActivityChipModel.Active.ShortTimeDelta(
+ this.key,
+ icon,
+ colors,
+ time = this.promotedContent.time.time,
+ onClickListenerLegacy,
+ clickBehavior,
+ )
+ } else {
+ // Don't show a `when` time that's close to now or in the past because it's
+ // likely that the app didn't intentionally set the `when` time to be shown in
+ // the status bar chip.
+ // TODO(b/393369213): If a notification sets a `when` time in the future and
+ // then that time comes and goes, the chip *will* start showing times in the
+ // past. Not going to fix this right now because the Compose implementation
+ // automatically handles this for us and we're hoping to launch the notification
+ // chips at the same time as the Compose chips.
+ return OngoingActivityChipModel.Active.IconOnly(
+ this.key,
+ icon,
+ colors,
+ onClickListenerLegacy,
+ clickBehavior,
+ )
+ }
}
PromotedNotificationContentModel.When.Mode.CountUp -> {
return OngoingActivityChipModel.Active.Timer(
@@ -204,4 +228,12 @@ constructor(
)
)
}
+
+ companion object {
+ /**
+ * Notifications must have a `when` time of at least 1 minute in the future in order for the
+ * status bar chip to show the time.
+ */
+ private const val FUTURE_TIME_THRESHOLD_MILLIS = 60 * 1000
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
index d41353b2c176..20dec11577df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
@@ -408,11 +408,13 @@ object OngoingActivityChipBinder {
private fun View.setBackgroundPaddingForEmbeddedPaddingIcon() {
val sidePadding =
if (StatusBarNotifChips.isEnabled) {
- 0
- } else {
context.resources.getDimensionPixelSize(
R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon
)
+ } else {
+ context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon_legacy
+ )
}
setPaddingRelative(sidePadding, paddingTop, sidePadding, paddingBottom)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt
index 8443d106dfb1..5242feac898b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt
@@ -19,8 +19,6 @@ package com.android.systemui.statusbar.chips.ui.compose
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Measurable
@@ -39,7 +37,9 @@ import androidx.compose.ui.unit.constrain
import androidx.compose.ui.unit.dp
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.viewmodel.formatTimeRemainingData
import com.android.systemui.statusbar.chips.ui.viewmodel.rememberChronometerState
+import com.android.systemui.statusbar.chips.ui.viewmodel.rememberTimeRemainingState
import kotlin.math.min
@Composable
@@ -121,7 +121,26 @@ fun ChipContent(viewModel: OngoingActivityChipModel.Active, modifier: Modifier =
}
is OngoingActivityChipModel.Active.ShortTimeDelta -> {
- // TODO(b/372657935): Implement ShortTimeDelta content in compose.
+ val timeRemainingState = rememberTimeRemainingState(futureTimeMillis = viewModel.time)
+
+ timeRemainingState.timeRemainingData?.let {
+ val text = formatTimeRemainingData(it)
+ Text(
+ text = text,
+ style = textStyle,
+ color = textColor,
+ softWrap = false,
+ modifier =
+ modifier.hideTextIfDoesNotFit(
+ text = text,
+ textStyle = textStyle,
+ textMeasurer = textMeasurer,
+ maxTextWidth = maxTextWidth,
+ startPadding = startPadding,
+ endPadding = endPadding,
+ ),
+ )
+ }
}
is OngoingActivityChipModel.Active.IconOnly -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
index 1cdf6800fb97..efd402ead979 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
@@ -41,7 +41,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.android.compose.animation.Expandable
import com.android.compose.modifiers.thenIf
@@ -49,11 +48,18 @@ import com.android.systemui.animation.Expandable
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.common.ui.compose.load
import com.android.systemui.res.R
+import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
@Composable
-fun OngoingActivityChip(model: OngoingActivityChipModel.Active, modifier: Modifier = Modifier) {
+fun OngoingActivityChip(
+ model: OngoingActivityChipModel.Active,
+ iconViewStore: NotificationIconContainerViewBinder.IconViewStore?,
+ modifier: Modifier = Modifier,
+) {
when (val clickBehavior = model.clickBehavior) {
is OngoingActivityChipModel.ClickBehavior.ExpandAction -> {
// Wrap the chip in an Expandable so we can animate the expand transition.
@@ -65,15 +71,15 @@ fun OngoingActivityChip(model: OngoingActivityChipModel.Active, modifier: Modifi
),
modifier = modifier,
) { expandable ->
- ChipBody(model, onClick = { clickBehavior.onClick(expandable) })
+ ChipBody(model, iconViewStore, onClick = { clickBehavior.onClick(expandable) })
}
}
is OngoingActivityChipModel.ClickBehavior.ShowHeadsUpNotification -> {
- ChipBody(model, onClick = { clickBehavior.onClick() })
+ ChipBody(model, iconViewStore, onClick = { clickBehavior.onClick() })
}
is OngoingActivityChipModel.ClickBehavior.None -> {
- ChipBody(model, modifier = modifier)
+ ChipBody(model, iconViewStore, modifier = modifier)
}
}
}
@@ -81,12 +87,15 @@ fun OngoingActivityChip(model: OngoingActivityChipModel.Active, modifier: Modifi
@Composable
private fun ChipBody(
model: OngoingActivityChipModel.Active,
+ iconViewStore: NotificationIconContainerViewBinder.IconViewStore?,
modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null,
) {
val context = LocalContext.current
val isClickable = onClick != null
- val hasEmbeddedIcon = model.icon is OngoingActivityChipModel.ChipIcon.StatusBarView
+ val hasEmbeddedIcon =
+ model.icon is OngoingActivityChipModel.ChipIcon.StatusBarView ||
+ model.icon is OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon
val contentDescription =
when (val icon = model.icon) {
is OngoingActivityChipModel.ChipIcon.StatusBarView -> icon.contentDescription.load()
@@ -150,13 +159,18 @@ private fun ChipBody(
.padding(
horizontal =
if (hasEmbeddedIcon) {
- 0.dp
+ dimensionResource(
+ R.dimen
+ .ongoing_activity_chip_side_padding_for_embedded_padding_icon
+ )
} else {
dimensionResource(id = R.dimen.ongoing_activity_chip_side_padding)
}
),
) {
- model.icon?.let { ChipIcon(viewModel = it, colors = model.colors) }
+ model.icon?.let {
+ ChipIcon(viewModel = it, iconViewStore = iconViewStore, colors = model.colors)
+ }
val isIconOnly = model is OngoingActivityChipModel.Active.IconOnly
if (!isIconOnly) {
@@ -169,6 +183,7 @@ private fun ChipBody(
@Composable
private fun ChipIcon(
viewModel: OngoingActivityChipModel.ChipIcon,
+ iconViewStore: NotificationIconContainerViewBinder.IconViewStore?,
colors: ColorsModel,
modifier: Modifier = Modifier,
) {
@@ -176,22 +191,16 @@ private fun ChipIcon(
when (viewModel) {
is OngoingActivityChipModel.ChipIcon.StatusBarView -> {
- // TODO(b/364653005): If the notification updates their small icon, ensure it's updated
- // in the chip.
- val originalIcon = viewModel.impl
- val iconSizePx =
- context.resources.getDimensionPixelSize(
- R.dimen.ongoing_activity_chip_embedded_padding_icon_size
- )
- AndroidView(
- modifier = modifier,
- factory = { _ ->
- originalIcon.apply {
- layoutParams = ViewGroup.LayoutParams(iconSizePx, iconSizePx)
- imageTintList = ColorStateList.valueOf(colors.text(context))
- }
- },
- )
+ StatusBarConnectedDisplays.assertInLegacyMode()
+ StatusBarIcon(colors, viewModel.impl.notification?.key, modifier) { viewModel.impl }
+ }
+ is OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon -> {
+ StatusBarConnectedDisplays.assertInNewMode()
+ check(iconViewStore != null)
+
+ StatusBarIcon(colors, viewModel.notificationKey, modifier) {
+ iconViewStore.iconView(viewModel.notificationKey)
+ }
}
is OngoingActivityChipModel.ChipIcon.SingleColorIcon -> {
@@ -209,6 +218,31 @@ private fun ChipIcon(
}
}
+/** A Compose wrapper around [StatusBarIconView]. */
+@Composable
+private fun StatusBarIcon(
+ colors: ColorsModel,
+ notificationKey: String?,
+ modifier: Modifier = Modifier,
+ iconFactory: () -> StatusBarIconView?,
+) {
+ val context = LocalContext.current
+
+ val iconSizePx =
+ context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_activity_chip_embedded_padding_icon_size
+ )
+ AndroidView(
+ modifier = modifier,
+ factory = { _ ->
+ iconFactory.invoke()?.apply {
+ layoutParams = ViewGroup.LayoutParams(iconSizePx, iconSizePx)
+ imageTintList = ColorStateList.valueOf(colors.text(context))
+ } ?: throw IllegalStateException("Missing StatusBarIconView for $notificationKey")
+ },
+ )
+}
+
@Composable
private fun ExpandableChip(
color: () -> Color,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
index 64cad31f2150..3b8c0f48e40e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
@@ -24,20 +24,30 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
+import androidx.compose.ui.res.dimensionResource
+import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
@Composable
-fun OngoingActivityChips(chips: MultipleOngoingActivityChipsModel, modifier: Modifier = Modifier) {
+fun OngoingActivityChips(
+ chips: MultipleOngoingActivityChipsModel,
+ iconViewStore: NotificationIconContainerViewBinder.IconViewStore?,
+ modifier: Modifier = Modifier,
+) {
Row(
- // TODO(b/372657935): Remove magic numbers for padding and spacing.
- modifier = modifier.fillMaxHeight().padding(horizontal = 6.dp),
+ modifier =
+ modifier
+ .fillMaxHeight()
+ .padding(start = dimensionResource(R.dimen.ongoing_activity_chip_margin_start)),
verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.spacedBy(8.dp),
+ horizontalArrangement =
+ Arrangement.spacedBy(dimensionResource(R.dimen.ongoing_activity_chip_margin_start)),
) {
- // TODO(b/372657935): Make sure chips are only shown when there is enough horizontal space.
chips.active
.filter { !it.isHidden }
- .forEach { key(it.key) { OngoingActivityChip(model = it) } }
+ .forEach {
+ key(it.key) { OngoingActivityChip(model = it, iconViewStore = iconViewStore) }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingState.kt
new file mode 100644
index 000000000000..eb6ebcaa5796
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/TimeRemainingState.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.ui.viewmodel
+
+import android.os.SystemClock
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.compose.LocalLifecycleOwner
+import androidx.lifecycle.repeatOnLifecycle
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.minutes
+import kotlin.time.DurationUnit
+import kotlin.time.toDuration
+import kotlinx.coroutines.delay
+
+/**
+ * Manages state and updates for the duration remaining between now and a given time in the future.
+ */
+class TimeRemainingState(private val timeSource: TimeSource, private val futureTimeMillis: Long) {
+ private var durationRemaining by mutableStateOf(Duration.ZERO)
+ private var startTimeMillis: Long = 0
+
+ /**
+ * [Pair] representing the time unit and its value.
+ *
+ * @property first the string resource ID corresponding to the time unit (e.g., minutes, hours).
+ * @property second the time value of the duration unit. Null if time is less than a minute or
+ * past.
+ */
+ val timeRemainingData by derivedStateOf { getTimeRemainingData(durationRemaining) }
+
+ suspend fun run() {
+ startTimeMillis = timeSource.getCurrentTime()
+ while (true) {
+ val currentTime = timeSource.getCurrentTime()
+ durationRemaining =
+ (futureTimeMillis - currentTime).toDuration(DurationUnit.MILLISECONDS)
+ // No need to update if duration is more than 1 minute in the past. Because, we will
+ // stop displaying anything.
+ if (durationRemaining.inWholeMilliseconds < -1.minutes.inWholeMilliseconds) {
+ break
+ }
+ val delaySkewMillis = (currentTime - startTimeMillis) % 1000L
+ delay(calculateNextUpdateDelay(durationRemaining) - delaySkewMillis)
+ }
+ }
+
+ private fun calculateNextUpdateDelay(duration: Duration): Long {
+ val durationAbsolute = duration.absoluteValue
+ return when {
+ durationAbsolute.inWholeHours < 1 -> {
+ 1000 + ((durationAbsolute.inWholeMilliseconds % 1.minutes.inWholeMilliseconds))
+ }
+ durationAbsolute.inWholeHours < 24 -> {
+ 1000 + (durationAbsolute.inWholeMilliseconds % 1.hours.inWholeMilliseconds)
+ }
+ else -> 1000 + (durationAbsolute.inWholeMilliseconds % 24.hours.inWholeMilliseconds)
+ }
+ }
+}
+
+/** Remember and manage the TimeRemainingState */
+@Composable
+fun rememberTimeRemainingState(
+ futureTimeMillis: Long,
+ timeSource: TimeSource = remember { TimeSource { SystemClock.elapsedRealtime() } },
+): TimeRemainingState {
+
+ val state =
+ remember(timeSource, futureTimeMillis) { TimeRemainingState(timeSource, futureTimeMillis) }
+ val lifecycleOwner = LocalLifecycleOwner.current
+ LaunchedEffect(lifecycleOwner, timeSource, futureTimeMillis) {
+ lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { state.run() }
+ }
+
+ return state
+}
+
+private fun getTimeRemainingData(duration: Duration): Pair<Int, Long?>? {
+ return when {
+ duration.inWholeMinutes <= -1 -> null
+ duration.inWholeMinutes < 1 -> Pair(com.android.internal.R.string.now_string_shortest, null)
+ duration.inWholeHours < 1 ->
+ Pair(com.android.internal.R.string.duration_minutes_medium, duration.inWholeMinutes)
+ duration.inWholeDays < 1 ->
+ Pair(com.android.internal.R.string.duration_hours_medium, duration.inWholeHours)
+ else -> null
+ }
+}
+
+/** Formats the time remaining data into a user-readable string. */
+@Composable
+fun formatTimeRemainingData(resourcePair: Pair<Int, Long?>): String {
+ return resourcePair.let { (resourceId, time) ->
+ when (time) {
+ null -> stringResource(resourceId)
+ else -> stringResource(resourceId, time.toInt())
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
index ea1d7820c79c..5887eb6ad865 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
@@ -25,6 +25,8 @@ import com.android.systemui.privacy.OngoingPrivacyChip
import com.android.systemui.privacy.PrivacyItem
import com.android.systemui.statusbar.BatteryStatusChip
import com.android.systemui.statusbar.ConnectedDisplayChip
+import com.android.systemui.statusbar.core.NewStatusBarIcons
+import com.android.systemui.statusbar.events.ui.view.BatteryStatusEventComposeChip
typealias ViewCreator = (context: Context) -> BackgroundAnimatableView
@@ -53,9 +55,7 @@ interface StatusEvent {
}
}
-class BGView(
- context: Context
-) : View(context), BackgroundAnimatableView {
+class BGView(context: Context) : View(context), BackgroundAnimatableView {
override val view: View
get() = this
@@ -65,9 +65,7 @@ class BGView(
}
@SuppressLint("AppCompatCustomView")
-class BGImageView(
- context: Context
-) : ImageView(context), BackgroundAnimatableView {
+class BGImageView(context: Context) : ImageView(context), BackgroundAnimatableView {
override val view: View
get() = this
@@ -84,8 +82,10 @@ class BatteryEvent(@IntRange(from = 0, to = 100) val batteryLevel: Int) : Status
override val shouldAnnounceAccessibilityEvent: Boolean = false
override val viewCreator: ViewCreator = { context ->
- BatteryStatusChip(context).apply {
- setBatteryLevel(batteryLevel)
+ if (NewStatusBarIcons.isEnabled) {
+ BatteryStatusEventComposeChip(batteryLevel, context)
+ } else {
+ BatteryStatusChip(context).apply { setBatteryLevel(batteryLevel) }
}
}
@@ -103,9 +103,7 @@ class ConnectedDisplayEvent : StatusEvent {
override var contentDescription: String? = ""
override val shouldAnnounceAccessibilityEvent: Boolean = true
- override val viewCreator: ViewCreator = { context ->
- ConnectedDisplayChip(context)
- }
+ override val viewCreator: ViewCreator = { context -> ConnectedDisplayChip(context) }
override fun toString(): String {
return javaClass.simpleName
@@ -134,7 +132,8 @@ open class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEven
}
override fun shouldUpdateFromEvent(other: StatusEvent?): Boolean {
- return other is PrivacyEvent && (other.privacyItems != privacyItems ||
+ return other is PrivacyEvent &&
+ (other.privacyItems != privacyItems ||
other.contentDescription != contentDescription ||
(other.forceVisible && !forceVisible))
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt
new file mode 100644
index 000000000000..a90e3ff4b2dc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.events.ui.view
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.core.NewStatusBarIcons
+import com.android.systemui.statusbar.events.BackgroundAnimatableView
+import com.android.systemui.statusbar.pipeline.battery.domain.interactor.BatteryInteractor
+import com.android.systemui.statusbar.pipeline.battery.shared.ui.BatteryColors.LightThemeChargingColors
+import com.android.systemui.statusbar.pipeline.battery.shared.ui.BatteryFrame
+import com.android.systemui.statusbar.pipeline.battery.shared.ui.BatteryGlyph
+import com.android.systemui.statusbar.pipeline.battery.ui.composable.BatteryCanvas
+import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel
+import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel.Companion.glyphRepresentation
+
+/**
+ * [StatusEvent] chip for the battery plugged in status event. Shows the current battery level and
+ * charging state in the status bar via the system event animation.
+ *
+ * This chip will fully replace [BatteryStatusChip] when [NewStatusBarIcons] is rolled out
+ */
+@SuppressLint("ViewConstructor")
+class BatteryStatusEventComposeChip
+@JvmOverloads
+constructor(level: Int, context: Context, attrs: AttributeSet? = null) :
+ FrameLayout(context, attrs), BackgroundAnimatableView {
+ private val roundedContainer: LinearLayout
+ private val composeInner: ComposeView
+ override val contentView: View
+ get() = composeInner
+
+ init {
+ NewStatusBarIcons.assertInNewMode()
+
+ inflate(context, R.layout.status_bar_event_chip_compose, this)
+ roundedContainer = requireViewById(R.id.rounded_container)
+ composeInner = requireViewById(R.id.compose_view)
+ composeInner.apply {
+ setContent {
+ val isFull = BatteryInteractor.isBatteryFull(level)
+ BatteryCanvas(
+ modifier =
+ Modifier.width(BatteryViewModel.STATUS_BAR_BATTERY_WIDTH)
+ .height(BatteryViewModel.STATUS_BAR_BATTERY_HEIGHT),
+ path = BatteryFrame.pathSpec,
+ // TODO(b/394659067): get a content description for this chip
+ contentDescription = "",
+ innerWidth = BatteryFrame.innerWidth,
+ innerHeight = BatteryFrame.innerHeight,
+ // This event only happens when plugged in, so we always show it as charging
+ glyphs =
+ if (isFull) listOf(BatteryGlyph.Bolt)
+ else level.glyphRepresentation() + BatteryGlyph.Bolt,
+ level = level,
+ isFull = isFull,
+ colorsProvider = { LightThemeChargingColors },
+ )
+ }
+ }
+ updateResources()
+ }
+
+ /**
+ * When animating as a chip in the status bar, we want to animate the width for the rounded
+ * container. We have to subtract our own top and left offset because the bounds come to us as
+ * absolute on-screen bounds.
+ */
+ override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
+ roundedContainer.setLeftTopRightBottom(l - left, t - top, r - left, b - top)
+ }
+
+ @SuppressLint("UseCompatLoadingForDrawables")
+ private fun updateResources() {
+ roundedContainer.background = mContext.getDrawable(R.drawable.statusbar_chip_bg)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/MediaControlChipStartable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/MediaControlChipStartable.kt
new file mode 100644
index 000000000000..e7bc052114eb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/MediaControlChipStartable.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.featurepods.media
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.featurepods.media.domain.interactor.MediaControlChipInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * A [CoreStartable] that initializes and starts the media control chip functionality. The media
+ * chip is limited to large screen devices currently. Therefore, this [CoreStartable] should not be
+ * used for phones or smaller form factor devices.
+ */
+@SysUISingleton
+class MediaControlChipStartable
+@Inject
+constructor(
+ @Background val bgScope: CoroutineScope,
+ private val mediaControlChipInteractor: MediaControlChipInteractor,
+) : CoreStartable {
+
+ override fun start() {
+ bgScope.launch { mediaControlChipInteractor.initialize() }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractor.kt
index e3e77e16be6d..f439bb297de0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/domain/interactor/MediaControlChipInteractor.kt
@@ -22,13 +22,15 @@ import com.android.systemui.media.controls.data.repository.MediaFilterRepository
import com.android.systemui.media.controls.shared.model.MediaCommonModel
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.featurepods.media.shared.model.MediaControlChipModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/**
@@ -37,6 +39,8 @@ import kotlinx.coroutines.flow.stateIn
* Provides a [StateFlow] of [MediaControlChipModel] representing the current state of the media
* control chip. Emits a new [MediaControlChipModel] when there is an active media session and the
* corresponding user preference is found, otherwise emits null.
+ *
+ * This functionality is only enabled on large screen devices.
*/
@SysUISingleton
class MediaControlChipInteractor
@@ -45,30 +49,57 @@ constructor(
@Background private val backgroundScope: CoroutineScope,
mediaFilterRepository: MediaFilterRepository,
) {
- private val currentMediaControls: StateFlow<List<MediaCommonModel.MediaControl>> =
- mediaFilterRepository.currentMedia
- .map { mediaList -> mediaList.filterIsInstance<MediaCommonModel.MediaControl>() }
- .stateIn(
- scope = backgroundScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = emptyList(),
- )
+ private val isEnabled = MutableStateFlow(false)
+
+ private val mediaControlChipModelForScene: Flow<MediaControlChipModel?> =
+ combine(mediaFilterRepository.currentMedia, mediaFilterRepository.selectedUserEntries) {
+ mediaList,
+ userEntries ->
+ mediaList
+ .filterIsInstance<MediaCommonModel.MediaControl>()
+ .mapNotNull { userEntries[it.mediaLoadedModel.instanceId] }
+ .firstOrNull { it.active }
+ ?.toMediaControlChipModel()
+ }
+
+ /**
+ * A flow of [MediaControlChipModel] representing the current state of the media controls chip.
+ * This flow emits null when no active media is playing or when playback information is
+ * unavailable. This flow is only active when [SceneContainerFlag] is disabled.
+ */
+ private val mediaControlChipModelLegacy = MutableStateFlow<MediaControlChipModel?>(null)
+
+ fun updateMediaControlChipModelLegacy(mediaData: MediaData?) {
+ if (!SceneContainerFlag.isEnabled) {
+ mediaControlChipModelLegacy.value = mediaData?.toMediaControlChipModel()
+ }
+ }
+
+ private val _mediaControlChipModel: Flow<MediaControlChipModel?> =
+ if (SceneContainerFlag.isEnabled) {
+ mediaControlChipModelForScene
+ } else {
+ mediaControlChipModelLegacy
+ }
/** The currently active [MediaControlChipModel] */
- val mediaControlModel: StateFlow<MediaControlChipModel?> =
- combine(currentMediaControls, mediaFilterRepository.selectedUserEntries) {
- mediaControls,
- userEntries ->
- mediaControls
- .mapNotNull { userEntries[it.mediaLoadedModel.instanceId] }
- .firstOrNull { it.active }
- ?.toMediaControlChipModel()
+ val mediaControlChipModel: StateFlow<MediaControlChipModel?> =
+ combine(_mediaControlChipModel, isEnabled) { mediaControlChipModel, isEnabled ->
+ if (isEnabled) {
+ mediaControlChipModel
+ } else {
+ null
+ }
}
- .stateIn(
- scope = backgroundScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = null,
- )
+ .stateIn(backgroundScope, SharingStarted.WhileSubscribed(), null)
+
+ /**
+ * The media control chip may not be enabled on all form factors, so only the relevant form
+ * factors should initialize the interactor. This must be called from a CoreStartable.
+ */
+ fun initialize() {
+ isEnabled.value = true
+ }
}
private fun MediaData.toMediaControlChipModel(): MediaControlChipModel {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
index 19acb2e9839c..90f97df295f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
@@ -55,8 +55,8 @@ constructor(
* whenever the underlying [MediaControlChipModel] changes.
*/
override val chip: StateFlow<PopupChipModel> =
- mediaControlChipInteractor.mediaControlModel
- .map { mediaControlModel -> toPopupChipModel(mediaControlModel) }
+ mediaControlChipInteractor.mediaControlChipModel
+ .map { mediaControlChipModel -> toPopupChipModel(mediaControlChipModel) }
.stateIn(
backgroundScope,
SharingStarted.WhileSubscribed(),
@@ -82,10 +82,6 @@ constructor(
chipId = PopupChipId.MediaControl,
icon = defaultIcon,
chipText = model.songName.toString(),
- isToggled = false,
- // TODO(b/385202114): Show a popup containing the media carousal when the chip is
- // toggled.
- onToggle = {},
hoverBehavior = createHoverBehavior(model),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt
index 683b97166f3e..60615536ab67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt
@@ -53,10 +53,11 @@ sealed class PopupChipModel {
/** Default icon displayed on the chip */
val icon: Icon,
val chipText: String,
- val isToggled: Boolean = false,
- val onToggle: () -> Unit,
+ val isPopupShown: Boolean = false,
+ val showPopup: () -> Unit = {},
+ val hidePopup: () -> Unit = {},
val hoverBehavior: HoverBehavior = HoverBehavior.None,
) : PopupChipModel() {
- override val logName = "Shown(id=$chipId, toggled=$isToggled)"
+ override val logName = "Shown(id=$chipId, toggled=$isPopupShown)"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt
new file mode 100644
index 000000000000..8a66904ea59b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.featurepods.popups.ui.compose
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.PopupProperties
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
+import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
+
+/**
+ * Displays a popup in the status bar area. The offset is calculated to draw the popup below the
+ * status bar.
+ */
+@Composable
+fun StatusBarPopup(viewModel: PopupChipModel.Shown) {
+ val density = Density(LocalContext.current)
+ Popup(
+ properties =
+ PopupProperties(
+ focusable = false,
+ dismissOnBackPress = true,
+ dismissOnClickOutside = true,
+ ),
+ offset =
+ IntOffset(
+ x = 0,
+ y = with(density) { dimensionResource(R.dimen.status_bar_height).roundToPx() },
+ ),
+ onDismissRequest = { viewModel.hidePopup() },
+ ) {
+ Box(modifier = Modifier.padding(8.dp).wrapContentSize()) {
+ when (viewModel.chipId) {
+ is PopupChipId.MediaControl -> {
+ // TODO(b/385202114): Populate MediaControlPopup contents.
+ }
+ }
+ // Future popup types will be handled here.
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt
index 34bef9d3ca3a..eb85d2f32f29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt
@@ -52,14 +52,14 @@ import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipM
* the chip can show text containing contextual information.
*/
@Composable
-fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifier) {
- val hasHoverBehavior = model.hoverBehavior !is HoverBehavior.None
+fun StatusBarPopupChip(viewModel: PopupChipModel.Shown, modifier: Modifier = Modifier) {
+ val hasHoverBehavior = viewModel.hoverBehavior !is HoverBehavior.None
val hoverInteractionSource = remember { MutableInteractionSource() }
val isHovered by hoverInteractionSource.collectIsHoveredAsState()
- val isToggled = model.isToggled
+ val isPopupShown = viewModel.isPopupShown
val chipBackgroundColor =
- if (isToggled) {
+ if (isPopupShown) {
MaterialTheme.colorScheme.primaryContainer
} else {
MaterialTheme.colorScheme.surfaceContainerHighest
@@ -72,7 +72,7 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie
.padding(vertical = 4.dp)
.animateContentSize()
.thenIf(hasHoverBehavior) { Modifier.hoverable(hoverInteractionSource) }
- .clickable { model.onToggle() },
+ .thenIf(!isPopupShown) { Modifier.clickable { viewModel.showPopup() } },
color = chipBackgroundColor,
) {
Row(
@@ -82,14 +82,14 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie
) {
val iconColor =
if (isHovered) chipBackgroundColor else contentColorFor(chipBackgroundColor)
- val hoverBehavior = model.hoverBehavior
+ val hoverBehavior = viewModel.hoverBehavior
val iconBackgroundColor = contentColorFor(chipBackgroundColor)
val iconInteractionSource = remember { MutableInteractionSource() }
Icon(
icon =
when {
isHovered && hoverBehavior is HoverBehavior.Button -> hoverBehavior.icon
- else -> model.icon
+ else -> viewModel.icon
},
modifier =
Modifier.thenIf(isHovered) {
@@ -109,7 +109,7 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie
)
Text(
- text = model.chipText,
+ text = viewModel.chipText,
style = MaterialTheme.typography.labelLarge,
softWrap = false,
overflow = TextOverflow.Ellipsis,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt
index d35674d8dd9f..16538c93cf35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt
@@ -31,10 +31,15 @@ fun StatusBarPopupChipsContainer(chips: List<PopupChipModel.Shown>, modifier: Mo
// TODO(b/385353140): Add padding and spacing for this container according to UX specs.
Box {
Row(
- modifier = Modifier.padding(horizontal = 8.dp),
+ modifier = modifier.padding(horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
- chips.forEach { chip -> StatusBarPopupChip(chip) }
+ chips.forEach { chip ->
+ StatusBarPopupChip(chip)
+ if (chip.isPopupShown) {
+ StatusBarPopup(chip)
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
index caa8e6cc02c3..33bf90defb48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
@@ -16,49 +16,65 @@
package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.MediaControlChipViewModel
import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
/**
* View model deciding which system process chips to show in the status bar. Emits a list of
* PopupChipModels.
*/
-@SysUISingleton
class StatusBarPopupChipsViewModel
-@Inject
-constructor(
- @Background scope: CoroutineScope,
- mediaControlChipViewModel: MediaControlChipViewModel,
-) {
- private data class PopupChipBundle(
- val media: PopupChipModel = PopupChipModel.Hidden(chipId = PopupChipId.MediaControl)
- )
+@AssistedInject
+constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable() {
+ private val hydrator: Hydrator = Hydrator("StatusBarPopupChipsViewModel.hydrator")
- private val incomingPopupChipBundle: StateFlow<PopupChipBundle?> =
- mediaControlChipViewModel.chip
- .map { chip -> PopupChipBundle(media = chip) }
- .stateIn(scope, SharingStarted.WhileSubscribed(), PopupChipBundle())
+ /** The ID of the current chip that is showing its popup, or `null` if no chip is shown. */
+ private var currentShownPopupChipId by mutableStateOf<PopupChipId?>(null)
- val shownPopupChips: StateFlow<List<PopupChipModel.Shown>> =
+ private val incomingPopupChipBundle: PopupChipBundle by
+ hydrator.hydratedStateOf(
+ traceName = "incomingPopupChipBundle",
+ initialValue = PopupChipBundle(),
+ source = mediaControlChip.chip.map { chip -> PopupChipBundle(media = chip) },
+ )
+
+ val shownPopupChips: List<PopupChipModel.Shown> by derivedStateOf {
if (StatusBarPopupChips.isEnabled) {
- incomingPopupChipBundle
- .map { bundle ->
- listOfNotNull(bundle?.media).filterIsInstance<PopupChipModel.Shown>()
- }
- .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
+ val bundle = incomingPopupChipBundle
+
+ listOfNotNull(bundle.media).filterIsInstance<PopupChipModel.Shown>().map { chip ->
+ chip.copy(
+ isPopupShown = chip.chipId == currentShownPopupChipId,
+ showPopup = { currentShownPopupChipId = chip.chipId },
+ hidePopup = { currentShownPopupChipId = null },
+ )
+ }
} else {
- MutableStateFlow(emptyList<PopupChipModel.Shown>()).asStateFlow()
+ emptyList()
}
+ }
+
+ override suspend fun onActivated(): Nothing {
+ hydrator.activate()
+ }
+
+ private data class PopupChipBundle(
+ val media: PopupChipModel = PopupChipModel.Hidden(chipId = PopupChipId.MediaControl)
+ )
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): StatusBarPopupChipsViewModel
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
index 37485feed792..0e3f103c152e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
@@ -16,11 +16,74 @@
package com.android.systemui.statusbar.notification.collection;
+import static android.app.NotificationChannel.NEWS_ID;
+import static android.app.NotificationChannel.PROMOTIONS_ID;
+import static android.app.NotificationChannel.RECS_ID;
+import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+
+import java.util.List;
+
/**
* Abstract class to represent notification section bundled by AI.
*/
public class BundleEntry extends PipelineEntry {
+ private final String mKey;
+ private final BundleEntryAdapter mEntryAdapter;
+
+ // TODO (b/389839319): implement the row
+ private ExpandableNotificationRow mRow;
+
+ public BundleEntry(String key) {
+ mKey = key;
+ mEntryAdapter = new BundleEntryAdapter();
+ }
+
+ @VisibleForTesting
+ public BundleEntryAdapter getEntryAdapter() {
+ return mEntryAdapter;
+ }
+
public class BundleEntryAdapter implements EntryAdapter {
+
+ /**
+ * TODO (b/394483200): convert to PipelineEntry.ROOT_ENTRY when pipeline is migrated?
+ */
+ @Override
+ public GroupEntry getParent() {
+ return GroupEntry.ROOT_ENTRY;
+ }
+
+ @Override
+ public boolean isTopLevelEntry() {
+ return true;
+ }
+
+ @Override
+ public String getKey() {
+ return mKey;
+ }
+
+ @Override
+ public ExpandableNotificationRow getRow() {
+ return mRow;
+ }
+
+ @Nullable
+ @Override
+ public EntryAdapter getGroupRoot() {
+ return this;
+ }
}
+
+ public static final List<BundleEntry> ROOT_BUNDLES = List.of(
+ new BundleEntry(PROMOTIONS_ID),
+ new BundleEntry(SOCIAL_MEDIA_ID),
+ new BundleEntry(NEWS_ID),
+ new BundleEntry(RECS_ID));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
index b12b1c538a32..4df81c97e21e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
@@ -16,8 +16,52 @@
package com.android.systemui.statusbar.notification.collection;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+
/**
* Adapter interface for UI to get relevant info.
*/
public interface EntryAdapter {
+
+ /**
+ * Gets the parent of this entry, or null if the entry's view is not attached
+ */
+ @Nullable PipelineEntry getParent();
+
+ /**
+ * Returns whether the entry is attached and appears at the top level of the shade
+ */
+ boolean isTopLevelEntry();
+
+ /**
+ * @return the unique identifier for this entry
+ */
+ @NonNull String getKey();
+
+ /**
+ * Gets the view that this entry is backing.
+ */
+ @NonNull
+ ExpandableNotificationRow getRow();
+
+ /**
+ * Gets the EntryAdapter that is the nearest root of the collection of rows the given entry
+ * belongs to. If the given entry is a BundleEntry or an isolated child of a BundleEntry, the
+ * BundleEntry will be returned. If the given notification is a group summary NotificationEntry,
+ * or a child of a group summary, the summary NotificationEntry will be returned, even if that
+ * summary belongs to a BundleEntry. If the entry is a notification that does not belong to any
+ * group or bundle grouping, null will be returned.
+ */
+ @Nullable
+ EntryAdapter getGroupRoot();
+
+ /**
+ * Returns whether the entry is attached to the current shade list
+ */
+ default boolean isAttached() {
+ return getParent() != null;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
index fc47dc1ed81a..8f3c357a277a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -24,6 +24,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.NotifInf
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import javax.inject.Inject;
@@ -78,7 +79,7 @@ public class NotifInflaterImpl implements NotifInflater {
requireBinder().inflateViews(
entry,
params,
- wrapInflationCallback(callback));
+ wrapInflationCallback(entry, callback));
} catch (InflationException e) {
mLogger.logInflationException(entry, e);
mNotifErrorManager.setInflationError(entry, e);
@@ -101,17 +102,26 @@ public class NotifInflaterImpl implements NotifInflater {
}
private NotificationRowContentBinder.InflationCallback wrapInflationCallback(
+ final NotificationEntry entry,
InflationCallback callback) {
return new NotificationRowContentBinder.InflationCallback() {
@Override
public void handleInflationException(
NotificationEntry entry,
Exception e) {
+ if (NotificationBundleUi.isEnabled()) {
+ handleInflationException(e);
+ } else {
+ mNotifErrorManager.setInflationError(entry, e);
+ }
+ }
+ @Override
+ public void handleInflationException(Exception e) {
mNotifErrorManager.setInflationError(entry, e);
}
@Override
- public void onAsyncInflationFinished(NotificationEntry entry) {
+ public void onAsyncInflationFinished() {
mNotifErrorManager.clearInflationError(entry);
if (callback != null) {
callback.onInflationFinished(entry, entry.getRowController());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 7dd82a6b5198..90f9525c7683 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -29,6 +29,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICAT
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static com.android.systemui.statusbar.notification.collection.BundleEntry.ROOT_BUNDLES;
+import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
@@ -107,6 +109,7 @@ public final class NotificationEntry extends ListEntry {
private final String mKey;
private StatusBarNotification mSbn;
private Ranking mRanking;
+ private final NotifEntryAdapter mEntryAdapter;
/*
* Bookkeeping members
@@ -268,9 +271,48 @@ public final class NotificationEntry extends ListEntry {
mKey = sbn.getKey();
setSbn(sbn);
setRanking(ranking);
+ mEntryAdapter = new NotifEntryAdapter();
}
public class NotifEntryAdapter implements EntryAdapter {
+ @Override
+ public PipelineEntry getParent() {
+ return NotificationEntry.this.getParent();
+ }
+
+ @Override
+ public boolean isTopLevelEntry() {
+ return getParent() != null
+ && (getParent() == ROOT_ENTRY || ROOT_BUNDLES.contains(getParent()));
+ }
+
+ @Override
+ public String getKey() {
+ return NotificationEntry.this.getKey();
+ }
+
+ @Override
+ public ExpandableNotificationRow getRow() {
+ return NotificationEntry.this.getRow();
+ }
+
+ @Nullable
+ @Override
+ public EntryAdapter getGroupRoot() {
+ // TODO (b/395857098): for backwards compatibility this will return null if called
+ // on a group summary that's not in a bundles, but it should return itself.
+ if (isTopLevelEntry() || getParent() == null) {
+ return null;
+ }
+ if (NotificationEntry.this.getParent().getSummary() != null) {
+ return NotificationEntry.this.getParent().getSummary().mEntryAdapter;
+ }
+ return null;
+ }
+ }
+
+ public EntryAdapter getEntryAdapter() {
+ return mEntryAdapter;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineEntry.java
index efedfef5cbe9..c5a479180329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineEntry.java
@@ -19,5 +19,5 @@ package com.android.systemui.statusbar.notification.collection;
/**
* Class to represent a notification, group, or bundle in the pipeline.
*/
-public class PipelineEntry {
+public abstract class PipelineEntry {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java
index 733b986b5422..9df4bf4af4e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java
@@ -23,6 +23,7 @@ import android.app.Notification;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -31,29 +32,50 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
+import com.android.systemui.statusbar.notification.promoted.domain.interactor.PromotedNotificationsInteractor;
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
+import com.android.systemui.util.kotlin.JavaAdapterKt;
-import com.google.common.primitives.Booleans;
+import kotlinx.coroutines.CoroutineScope;
+
+import java.util.Collections;
+import java.util.List;
import javax.inject.Inject;
/**
* Handles sectioning for foreground service notifications.
- * Puts non-min colorized foreground service notifications into the FGS section. See
- * {@link NotifCoordinators} for section ordering priority.
+ * Puts non-min colorized foreground service notifications into the FGS section. See
+ * {@link NotifCoordinators} for section ordering priority.
*/
@CoordinatorScope
public class ColorizedFgsCoordinator implements Coordinator {
private static final String TAG = "ColorizedCoordinator";
+ private final PromotedNotificationsInteractor mPromotedNotificationsInteractor;
+ private final CoroutineScope mMainScope;
+
+ private List<String> mOrderedPromotedNotifKeys = Collections.emptyList();
@Inject
- public ColorizedFgsCoordinator() {
+ public ColorizedFgsCoordinator(
+ @Application CoroutineScope mainScope,
+ PromotedNotificationsInteractor promotedNotificationsInteractor
+ ) {
+ mPromotedNotificationsInteractor = promotedNotificationsInteractor;
+ mMainScope = mainScope;
}
@Override
- public void attach(NotifPipeline pipeline) {
+ public void attach(@NonNull NotifPipeline pipeline) {
if (PromotedNotificationUi.isEnabled()) {
pipeline.addPromoter(mPromotedOngoingPromoter);
+
+ JavaAdapterKt.collectFlow(mMainScope,
+ mPromotedNotificationsInteractor.getOrderedChipNotificationKeys(),
+ (List<String> keys) -> {
+ mOrderedPromotedNotifKeys = keys;
+ mNotifSectioner.invalidateList("updated mOrderedPromotedNotifKeys");
+ });
}
}
@@ -82,12 +104,24 @@ public class ColorizedFgsCoordinator implements Coordinator {
return false;
}
- private NotifComparator mPreferPromoted = new NotifComparator("PreferPromoted") {
+ /** get the sort key for any entry in the ongoing section */
+ private int getSortKey(@Nullable NotificationEntry entry) {
+ if (entry == null) return Integer.MAX_VALUE;
+ // Order all promoted notif keys first, using their order in the list
+ final int index = mOrderedPromotedNotifKeys.indexOf(entry.getKey());
+ if (index >= 0) return index;
+ // Next, prioritize promoted ongoing over other notifications
+ return isPromotedOngoing(entry) ? Integer.MAX_VALUE - 1 : Integer.MAX_VALUE;
+ }
+
+ private final NotifComparator mOngoingComparator = new NotifComparator(
+ "OngoingComparator") {
@Override
public int compare(@NonNull ListEntry o1, @NonNull ListEntry o2) {
- return -1 * Booleans.compare(
- isPromotedOngoing(o1.getRepresentativeEntry()),
- isPromotedOngoing(o2.getRepresentativeEntry()));
+ return Integer.compare(
+ getSortKey(o1.getRepresentativeEntry()),
+ getSortKey(o2.getRepresentativeEntry())
+ );
}
};
@@ -95,7 +129,7 @@ public class ColorizedFgsCoordinator implements Coordinator {
@Override
public NotifComparator getComparator() {
if (PromotedNotificationUi.isEnabled()) {
- return mPreferPromoted;
+ return mOngoingComparator;
} else {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
index d47fe20911f9..2e3ab926ad57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -27,6 +27,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import java.util.List;
@@ -129,21 +130,42 @@ public class HighPriorityProvider {
>= NotificationManager.IMPORTANCE_DEFAULT);
}
+ /**
+ * Returns whether the given ListEntry has a high priority child or is in a group with a child
+ * that's high priority
+ */
private boolean hasHighPriorityChild(ListEntry entry, boolean allowImplicit) {
- if (entry instanceof NotificationEntry
- && !mGroupMembershipManager.isGroupSummary((NotificationEntry) entry)) {
- return false;
- }
-
- List<NotificationEntry> children = mGroupMembershipManager.getChildren(entry);
- if (children != null) {
- for (NotificationEntry child : children) {
- if (child != entry && isHighPriority(child, allowImplicit)) {
- return true;
+ if (NotificationBundleUi.isEnabled()) {
+ GroupEntry representativeGroupEntry = null;
+ if (entry instanceof GroupEntry) {
+ representativeGroupEntry = (GroupEntry) entry;
+ } else if (entry instanceof NotificationEntry){
+ final NotificationEntry notificationEntry = entry.getRepresentativeEntry();
+ if (notificationEntry.getParent() != null
+ && notificationEntry.getParent().getSummary() != null
+ && notificationEntry.getParent().getSummary() == notificationEntry) {
+ representativeGroupEntry = notificationEntry.getParent();
}
}
+ return representativeGroupEntry != null &&
+ representativeGroupEntry.getChildren().stream().anyMatch(
+ childEntry -> isHighPriority(childEntry, allowImplicit));
+
+ } else {
+ if (entry instanceof NotificationEntry
+ && !mGroupMembershipManager.isGroupSummary((NotificationEntry) entry)) {
+ return false;
+ }
+ List<NotificationEntry> children = mGroupMembershipManager.getChildren(entry);
+ if (children != null) {
+ for (NotificationEntry child : children) {
+ if (child != entry && isHighPriority(child, allowImplicit)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
- return false;
}
private boolean hasHighPriorityCharacteristics(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java
index 30386ab46382..ea369463da51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.render;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -38,6 +39,20 @@ public interface GroupExpansionManager {
boolean isGroupExpanded(NotificationEntry entry);
/**
+ * Whether the parent associated with this notification is expanded.
+ * If this notification is not part of a group or bundle, it will always return false.
+ */
+ boolean isGroupExpanded(EntryAdapter entry);
+
+ /**
+ * Set whether the group/bundle associated with this notification is expanded or not.
+ */
+ void setGroupExpanded(EntryAdapter entry, boolean expanded);
+
+ /** @return group/bundle expansion state after toggling. */
+ boolean toggleGroupExpansion(EntryAdapter entry);
+
+ /**
* Set whether the group associated with this notification is expanded or not.
*/
void setGroupExpanded(NotificationEntry entry, boolean expanded);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
index d1aff80b4e7c..16b98e20498a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
@@ -23,11 +23,13 @@ import androidx.annotation.NonNull;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -55,6 +57,8 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl
*/
private final Set<NotificationEntry> mExpandedGroups = new HashSet<>();
+ private final Set<EntryAdapter> mExpandedCollections = new HashSet<>();
+
@Inject
public GroupExpansionManagerImpl(DumpManager dumpManager,
GroupMembershipManager groupMembershipManager) {
@@ -63,11 +67,17 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl
}
/**
- * Cleanup entries from mExpandedGroups that no longer exist in the pipeline.
+ * Cleanup entries from internal tracking that no longer exist in the pipeline.
*/
private final OnBeforeRenderListListener mNotifTracker = (entries) -> {
- if (mExpandedGroups.isEmpty()) {
- return; // nothing to do
+ if (NotificationBundleUi.isEnabled()) {
+ if (mExpandedCollections.isEmpty()) {
+ return; // nothing to do
+ }
+ } else {
+ if (mExpandedGroups.isEmpty()) {
+ return; // nothing to do
+ }
}
final Set<NotificationEntry> renderingSummaries = new HashSet<>();
@@ -77,10 +87,25 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl
}
}
- // If a group is in mExpandedGroups but not in the pipeline entries, collapse it.
- final var groupsToRemove = setDifference(mExpandedGroups, renderingSummaries);
- for (NotificationEntry entry : groupsToRemove) {
- setGroupExpanded(entry, false);
+ if (NotificationBundleUi.isEnabled()) {
+ for (EntryAdapter entryAdapter : mExpandedCollections) {
+ boolean isInPipeline = false;
+ for (NotificationEntry entry : renderingSummaries) {
+ if (entry.getKey().equals(entryAdapter.getKey())) {
+ isInPipeline = true;
+ break;
+ }
+ }
+ if (!isInPipeline) {
+ setGroupExpanded(entryAdapter, false);
+ }
+ }
+ } else {
+ // If a group is in mExpandedGroups but not in the pipeline entries, collapse it.
+ final var groupsToRemove = setDifference(mExpandedGroups, renderingSummaries);
+ for (NotificationEntry entry : groupsToRemove) {
+ setGroupExpanded(entry, false);
+ }
}
};
@@ -96,11 +121,13 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl
@Override
public boolean isGroupExpanded(NotificationEntry entry) {
+ NotificationBundleUi.assertInLegacyMode();
return mExpandedGroups.contains(mGroupMembershipManager.getGroupSummary(entry));
}
@Override
public void setGroupExpanded(NotificationEntry entry, boolean expanded) {
+ NotificationBundleUi.assertInLegacyMode();
NotificationEntry groupSummary = mGroupMembershipManager.getGroupSummary(entry);
if (entry.getParent() == null) {
if (expanded) {
@@ -127,14 +154,61 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl
@Override
public boolean toggleGroupExpansion(NotificationEntry entry) {
+ NotificationBundleUi.assertInLegacyMode();
+ setGroupExpanded(entry, !isGroupExpanded(entry));
+ return isGroupExpanded(entry);
+ }
+
+ @Override
+ public boolean isGroupExpanded(EntryAdapter entry) {
+ NotificationBundleUi.assertInNewMode();
+ return mExpandedCollections.contains(mGroupMembershipManager.getGroupRoot(entry));
+ }
+
+ @Override
+ public void setGroupExpanded(EntryAdapter entry, boolean expanded) {
+ NotificationBundleUi.assertInNewMode();
+ EntryAdapter groupParent = mGroupMembershipManager.getGroupRoot(entry);
+ if (!entry.isAttached()) {
+ if (expanded) {
+ Log.wtf(TAG, "Cannot expand group that is not attached");
+ } else {
+ // The entry is no longer attached, but we still want to make sure we don't have
+ // a stale expansion state.
+ groupParent = entry;
+ }
+ }
+
+ boolean changed;
+ if (expanded) {
+ changed = mExpandedCollections.add(groupParent);
+ } else {
+ changed = mExpandedCollections.remove(groupParent);
+ }
+
+ // Only notify listeners if something changed.
+ if (changed) {
+ sendOnGroupExpandedChange(entry, expanded);
+ }
+ }
+
+ @Override
+ public boolean toggleGroupExpansion(EntryAdapter entry) {
+ NotificationBundleUi.assertInNewMode();
setGroupExpanded(entry, !isGroupExpanded(entry));
return isGroupExpanded(entry);
}
@Override
public void collapseGroups() {
- for (NotificationEntry entry : new ArrayList<>(mExpandedGroups)) {
- setGroupExpanded(entry, false);
+ if (NotificationBundleUi.isEnabled()) {
+ for (EntryAdapter entry : new ArrayList<>(mExpandedCollections)) {
+ setGroupExpanded(entry, false);
+ }
+ } else {
+ for (NotificationEntry entry : new ArrayList<>(mExpandedGroups)) {
+ setGroupExpanded(entry, false);
+ }
}
}
@@ -145,9 +219,21 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl
for (NotificationEntry entry : mExpandedGroups) {
pw.println(" * " + entry.getKey());
}
+ pw.println(" mExpandedCollection: " + mExpandedCollections.size());
+ for (EntryAdapter entry : mExpandedCollections) {
+ pw.println(" * " + entry.getKey());
+ }
}
private void sendOnGroupExpandedChange(NotificationEntry entry, boolean expanded) {
+ NotificationBundleUi.assertInLegacyMode();
+ for (OnGroupExpansionChangeListener listener : mOnGroupChangeListeners) {
+ listener.onGroupExpansionChange(entry.getRow(), expanded);
+ }
+ }
+
+ private void sendOnGroupExpandedChange(EntryAdapter entry, boolean expanded) {
+ NotificationBundleUi.assertInNewMode();
for (OnGroupExpansionChangeListener listener : mOnGroupChangeListeners) {
listener.onGroupExpansionChange(entry.getRow(), expanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
index 3158782e6fea..69267e5d9e55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.collection.render;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -29,6 +30,13 @@ import java.util.List;
* generally assumes that the notification is attached (aka its parent is not null).
*/
public interface GroupMembershipManager {
+
+ /**
+ * @return whether a given entry is the root (GroupEntry or BundleEntry) in a collection which
+ * has children
+ */
+ boolean isGroupRoot(@NonNull EntryAdapter entry);
+
/**
* @return whether a given notification is the summary in a group which has children
*/
@@ -42,16 +50,15 @@ public interface GroupMembershipManager {
NotificationEntry getGroupSummary(@NonNull NotificationEntry entry);
/**
- * Similar to {@link #getGroupSummary(NotificationEntry)} but doesn't get the visual summary
- * but the logical summary, i.e when a child is isolated, it still returns the summary as if
- * it wasn't isolated.
- * TODO: remove this when migrating to the new pipeline, this is taken care of in the
- * dismissal logic built into NotifCollection
+ * Gets the EntryAdapter that is the nearest root of the collection of rows the given entry
+ * belongs to. If the given entry is a BundleEntry or an isolated child of a BundleEntry, the
+ * BundleEntry will be returned. If the given notification is a group summary NotificationEntry,
+ * or a child of a group summary, the summary NotificationEntry will be returned, even if that
+ * summary belongs to a BundleEntry. If the entry is a notification that does not belong to any
+ * group or bundle grouping, null will be returned.
*/
@Nullable
- default NotificationEntry getLogicalGroupSummary(@NonNull NotificationEntry entry) {
- return getGroupSummary(entry);
- }
+ EntryAdapter getGroupRoot(@NonNull EntryAdapter entry);
/**
* @return whether a given notification is a child in a group
@@ -59,9 +66,10 @@ public interface GroupMembershipManager {
boolean isChildInGroup(@NonNull NotificationEntry entry);
/**
- * Whether this is the only child in a group
+ * @return whether a given notification is a child in a group. The group may be a notification
+ * group or a bundle.
*/
- boolean isOnlyChildInGroup(@NonNull NotificationEntry entry);
+ boolean isChildInGroup(@NonNull EntryAdapter entry);
/**
* Get the children that are in the summary's group, not including those isolated.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
index da1247953c4c..80a9f8adf8f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
@@ -22,9 +22,11 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import java.util.List;
@@ -41,6 +43,7 @@ public class GroupMembershipManagerImpl implements GroupMembershipManager {
@Override
public boolean isGroupSummary(@NonNull NotificationEntry entry) {
+ NotificationBundleUi.assertInLegacyMode();
if (entry.getParent() == null) {
// The entry is not attached, so it doesn't count.
return false;
@@ -49,33 +52,47 @@ public class GroupMembershipManagerImpl implements GroupMembershipManager {
return entry.getParent().getSummary() == entry;
}
+ @Override
+ public boolean isGroupRoot(@NonNull EntryAdapter entry) {
+ NotificationBundleUi.assertInNewMode();
+ return entry == entry.getGroupRoot();
+ }
+
@Nullable
@Override
public NotificationEntry getGroupSummary(@NonNull NotificationEntry entry) {
+ NotificationBundleUi.assertInLegacyMode();
if (isTopLevelEntry(entry) || entry.getParent() == null) {
return null;
}
return entry.getParent().getSummary();
}
+ @Nullable
+ @Override
+ public EntryAdapter getGroupRoot(@NonNull EntryAdapter entry) {
+ NotificationBundleUi.assertInNewMode();
+ return entry.getGroupRoot();
+ }
+
@Override
public boolean isChildInGroup(@NonNull NotificationEntry entry) {
+ NotificationBundleUi.assertInLegacyMode();
// An entry is a child if it's not a summary or top level entry, but it is attached.
return !isGroupSummary(entry) && !isTopLevelEntry(entry) && entry.getParent() != null;
}
@Override
- public boolean isOnlyChildInGroup(@NonNull NotificationEntry entry) {
- if (entry.getParent() == null) {
- return false; // The entry is not attached.
- }
-
- return !isGroupSummary(entry) && entry.getParent().getChildren().size() == 1;
+ public boolean isChildInGroup(@NonNull EntryAdapter entry) {
+ NotificationBundleUi.assertInNewMode();
+ // An entry is a child if it's not a group root or top level entry, but it is attached.
+ return entry.isAttached() && entry != getGroupRoot(entry) && !entry.isTopLevelEntry();
}
@Nullable
@Override
public List<NotificationEntry> getChildren(@NonNull ListEntry entry) {
+ NotificationBundleUi.assertInLegacyMode();
if (entry instanceof GroupEntry) {
return ((GroupEntry) entry).getChildren();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationStackOptionalModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationStackOptionalModule.kt
deleted file mode 100644
index bcaf1878a869..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationStackOptionalModule.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2025 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.dagger
-
-import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHider
-import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHiderImpl
-import dagger.Binds
-import dagger.BindsOptionalOf
-import dagger.Module
-
-/**
- * This is meant to be bound in SystemUI variants with [NotificationStackScrollLayoutController].
- */
-@Module
-interface NotificationStackModule {
- @Binds
- fun bindNotificationStackRebindingHider(
- impl: NotificationStackRebindingHiderImpl
- ): NotificationStackRebindingHider
-}
-
-/** This is meant to be used by all SystemUI variants, also those without NSSL. */
-@Module
-interface NotificationStackOptionalModule {
- @BindsOptionalOf
- fun bindOptionalOfNotificationStackRebindingHider(): NotificationStackRebindingHider
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 34f4969127e3..53d5dbc58677 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -121,7 +121,6 @@ import javax.inject.Provider;
NotificationMemoryModule.class,
NotificationStatsLoggerModule.class,
NotificationsLogModule.class,
- NotificationStackOptionalModule.class,
})
public interface NotificationsModule {
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index 96192b1ea315..25deec375c03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -391,7 +391,7 @@ public class FooterView extends StackScrollerDecorView {
if (!notificationFooterBackgroundTintOptimization()) {
if (notificationShadeBlur()) {
Color backgroundColor = Color.valueOf(
- SurfaceEffectColors.surfaceEffect0(getResources()));
+ SurfaceEffectColors.surfaceEffect1(getResources()));
scHigh = ColorUtils.setAlphaComponent(backgroundColor.toArgb(), 0xFF);
// Apply alpha on background drawables.
int backgroundAlpha = (int) (backgroundColor.alpha() * 0xFF);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
index be61dc95fe20..7d74a496853f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
@@ -46,6 +46,7 @@ import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator;
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
@@ -55,6 +56,7 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -118,7 +120,8 @@ public class HeadsUpManagerImpl
@VisibleForTesting
final ArrayMap<String, HeadsUpEntry> mHeadsUpEntryMap = new ArrayMap<>();
private final HeadsUpManagerLogger mLogger;
- private final int mMinimumDisplayTime;
+ private final int mMinimumDisplayTimeDefault;
+ private final int mMinimumDisplayTimeForUserInitiated;
private final int mStickyForSomeTimeAutoDismissTime;
private final int mAutoDismissTime;
private final DelayableExecutor mExecutor;
@@ -215,9 +218,11 @@ public class HeadsUpManagerImpl
mGroupMembershipManager = groupMembershipManager;
mVisualStabilityProvider = visualStabilityProvider;
Resources resources = context.getResources();
- mMinimumDisplayTime = NotificationThrottleHun.isEnabled()
+ mMinimumDisplayTimeDefault = NotificationThrottleHun.isEnabled()
? resources.getInteger(R.integer.heads_up_notification_minimum_time_with_throttling)
: resources.getInteger(R.integer.heads_up_notification_minimum_time);
+ mMinimumDisplayTimeForUserInitiated = resources.getInteger(
+ R.integer.heads_up_notification_minimum_time_for_user_initiated);
mStickyForSomeTimeAutoDismissTime = resources.getInteger(
R.integer.sticky_heads_up_notification_time);
mAutoDismissTime = resources.getInteger(R.integer.heads_up_notification_decay);
@@ -871,14 +876,24 @@ public class HeadsUpManagerImpl
if (!hasPinnedHeadsUp() || topEntry == null) {
return null;
} else {
+ ExpandableNotificationRow topRow = topEntry.getRow();
if (topEntry.rowIsChildInGroup()) {
- final NotificationEntry groupSummary =
- mGroupMembershipManager.getGroupSummary(topEntry);
- if (groupSummary != null) {
- topEntry = groupSummary;
+ if (NotificationBundleUi.isEnabled()) {
+ final EntryAdapter adapter = mGroupMembershipManager.getGroupRoot(
+ topRow.getEntryAdapter());
+ if (adapter != null) {
+ topRow = adapter.getRow();
+ }
+ } else {
+ final NotificationEntry groupSummary =
+ mGroupMembershipManager.getGroupSummary(topEntry);
+ if (groupSummary != null) {
+ topEntry = groupSummary;
+ topRow = topEntry.getRow();
+ }
}
}
- ExpandableNotificationRow topRow = topEntry.getRow();
+
int[] tmpArray = new int[2];
topRow.getLocationOnScreen(tmpArray);
int minX = tmpArray[0];
@@ -1358,7 +1373,12 @@ public class HeadsUpManagerImpl
final long now = mSystemClock.elapsedRealtime();
if (updateEarliestRemovalTime) {
- mEarliestRemovalTime = now + mMinimumDisplayTime;
+ if (StatusBarNotifChips.isEnabled()
+ && mPinnedStatus.getValue() == PinnedStatus.PinnedByUser) {
+ mEarliestRemovalTime = now + mMinimumDisplayTimeForUserInitiated;
+ } else {
+ mEarliestRemovalTime = now + mMinimumDisplayTimeDefault;
+ }
}
if (updatePostTime) {
@@ -1377,7 +1397,7 @@ public class HeadsUpManagerImpl
final long now = mSystemClock.elapsedRealtime();
return NotificationThrottleHun.isEnabled()
? Math.max(finishTime, mEarliestRemovalTime) - now
- : Math.max(finishTime - now, mMinimumDisplayTime);
+ : Math.max(finishTime - now, mMinimumDisplayTimeDefault);
};
scheduleAutoRemovalCallback(finishTimeCalculator, "updateEntry (not sticky)");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
index 31375cc4a03a..c512b43c91a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
@@ -222,10 +222,6 @@ constructor(
return@traceSection
}
- if (StatusBarConnectedDisplays.isEnabled) {
- onIconUpdateRequiredListeners.onEach { it.onIconUpdateRequired(entry) }
- }
-
if (usingCache && !Flags.notificationsBackgroundIcons()) {
Log.wtf(
TAG,
@@ -238,6 +234,10 @@ constructor(
entry.icons.peopleAvatarDescriptor = null
}
+ if (StatusBarConnectedDisplays.isEnabled) {
+ onIconUpdateRequiredListeners.onEach { it.onIconUpdateRequired(entry) }
+ }
+
val (normalIconDescriptor, sensitiveIconDescriptor) = getIconDescriptors(entry)
val notificationContentDescription =
entry.sbn.notification?.let { iconBuilder.getIconContentDescription(it) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt
index f02edee399eb..18a1afa17720 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt
@@ -21,6 +21,7 @@ import com.android.systemui.statusbar.data.repository.NotificationListenerSettin
import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor
+import com.android.systemui.statusbar.notification.promoted.domain.interactor.AODPromotedNotificationInteractor
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
import com.android.wm.shell.bubbles.Bubbles
import java.util.Optional
@@ -30,6 +31,7 @@ import kotlin.jvm.optionals.getOrNull
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
/** Domain logic related to notification icons. */
@@ -39,8 +41,21 @@ constructor(
private val activeNotificationsInteractor: ActiveNotificationsInteractor,
private val bubbles: Optional<Bubbles>,
private val headsUpNotificationIconInteractor: HeadsUpNotificationIconInteractor,
+ private val aodPromotedNotificationInteractor: AODPromotedNotificationInteractor,
private val keyguardViewStateRepository: NotificationsKeyguardViewStateRepository,
) {
+ private val aodPromotedKeyToHide: Flow<String?> =
+ combine(
+ aodPromotedNotificationInteractor.content,
+ aodPromotedNotificationInteractor.isPresent,
+ ) { content, isPresent ->
+ when {
+ !isPresent -> null
+ content == null -> null
+ else -> content.identity.key
+ }
+ }
+
/** Returns a subset of all active notifications based on the supplied filtration parameters. */
fun filteredNotifSet(
forceShowHeadsUp: Boolean = false,
@@ -49,12 +64,14 @@ constructor(
showDismissed: Boolean = true,
showRepliedMessages: Boolean = true,
showPulsing: Boolean = true,
+ showAodPromoted: Boolean = true,
): Flow<Set<ActiveNotificationModel>> {
return combine(
activeNotificationsInteractor.topLevelRepresentativeNotifications,
headsUpNotificationIconInteractor.isolatedNotification,
+ if (showAodPromoted) flowOf(null) else aodPromotedKeyToHide,
keyguardViewStateRepository.areNotificationsFullyHidden,
- ) { notifications, isolatedNotifKey, notifsFullyHidden ->
+ ) { notifications, isolatedNotifKey, aodPromotedKeyToHide, notifsFullyHidden ->
notifications
.asSequence()
.filter { model: ActiveNotificationModel ->
@@ -67,6 +84,7 @@ constructor(
showRepliedMessages = showRepliedMessages,
showPulsing = showPulsing,
isolatedNotifKey = isolatedNotifKey,
+ aodPromotedKeyToHide = aodPromotedKeyToHide,
notifsFullyHidden = notifsFullyHidden,
)
}
@@ -83,6 +101,7 @@ constructor(
showRepliedMessages: Boolean,
showPulsing: Boolean,
isolatedNotifKey: String?,
+ aodPromotedKeyToHide: String?,
notifsFullyHidden: Boolean,
): Boolean {
return when {
@@ -93,6 +112,7 @@ constructor(
!showRepliedMessages && model.isLastMessageFromReply -> false
!showAmbient && model.isSuppressedFromStatusBar -> false
!showPulsing && model.isPulsing && !notifsFullyHidden -> false
+ model.key == aodPromotedKeyToHide -> false
bubbles.getOrNull()?.isBubbleExpanded(model.key) == true -> false
else -> true
}
@@ -115,6 +135,7 @@ constructor(
showDismissed = false,
showRepliedMessages = false,
showPulsing = !isBypassEnabled,
+ showAodPromoted = false,
)
}
.flowOn(bgContext)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index 691f1f452da8..f755dbb48e1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -27,6 +27,7 @@ import com.android.systemui.statusbar.notification.people.PeopleNotificationIden
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import javax.inject.Inject
import kotlin.math.max
@@ -112,14 +113,26 @@ class PeopleNotificationIdentifierImpl @Inject constructor(
if (personExtractor.isPersonNotification(sbn)) TYPE_PERSON else TYPE_NON_PERSON
private fun getPeopleTypeOfSummary(entry: NotificationEntry): Int {
- if (!groupManager.isGroupSummary(entry)) {
- return TYPE_NON_PERSON
+ if (NotificationBundleUi.isEnabled) {
+ if (!entry.sbn.notification.isGroupSummary) {
+ return TYPE_NON_PERSON;
+ }
+
+ return getPeopleTypeForChildList(entry.parent?.children)
+ } else {
+ if (!groupManager.isGroupSummary(entry)) {
+ return TYPE_NON_PERSON
+ }
+
+ return getPeopleTypeForChildList(groupManager.getChildren(entry))
}
+ }
- val childTypes = groupManager.getChildren(entry)
- ?.asSequence()
- ?.map { getPeopleNotificationType(it) }
- ?: return TYPE_NON_PERSON
+ private fun getPeopleTypeForChildList(children: List<NotificationEntry>?): Int {
+ val childTypes = children
+ ?.asSequence()
+ ?.map { getPeopleNotificationType(it) }
+ ?: return TYPE_NON_PERSON
var groupType = TYPE_NON_PERSON
for (childType in childTypes) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt
index 777ffda8c87d..893570b7fb51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt
@@ -23,6 +23,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
+import android.view.ViewGroup.MarginLayoutParams
import android.view.ViewStub
import android.widget.Chronometer
import android.widget.DateTimeView
@@ -38,7 +39,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
@@ -164,8 +164,8 @@ private class AODPromotedNotificationViewUpdater(root: View) {
private var chronometerStub: ViewStub? = root.findViewById(R.id.chronometer)
private var chronometer: Chronometer? = null
private val closeButton: View? = root.findViewById(R.id.close_button)
- private val conversationIconContainer: View? =
- root.findViewById(R.id.conversation_icon_container)
+ private val conversationIconBadge: View? = root.findViewById(R.id.conversation_icon_badge)
+ private val conversationIcon: CachingIconView? = root.findViewById(R.id.conversation_icon)
private val conversationText: TextView? = root.findViewById(R.id.conversation_text)
private val expandButton: NotificationExpandButton? = root.findViewById(R.id.expand_button)
private val headerText: TextView? = root.findViewById(R.id.header_text)
@@ -175,12 +175,13 @@ private class AODPromotedNotificationViewUpdater(root: View) {
root.findViewById(R.id.header_text_secondary_divider)
private val icon: NotificationRowIconView? = root.findViewById(R.id.icon)
private val leftIcon: ImageView? = root.findViewById(R.id.left_icon)
- private val rightIcon: ImageView? = root.findViewById(R.id.right_icon)
+ private val mainColumn: View? = root.findViewById(R.id.notification_main_column)
private val notificationProgressEndIcon: CachingIconView? =
root.findViewById(R.id.notification_progress_end_icon)
private val notificationProgressStartIcon: CachingIconView? =
root.findViewById(R.id.notification_progress_start_icon)
private val profileBadge: ImageView? = root.findViewById(R.id.profile_badge)
+ private val rightIcon: ImageView? = root.findViewById(R.id.right_icon)
private val text: ImageFloatingTextView? = root.findViewById(R.id.text)
private val time: DateTimeView? = root.findViewById(R.id.time)
private val timeDivider: View? = root.findViewById(R.id.time_divider)
@@ -198,7 +199,7 @@ private class AODPromotedNotificationViewUpdater(root: View) {
alternateExpandTarget?.visibility = GONE
bigPicture?.visibility = GONE
closeButton?.visibility = GONE
- conversationIconContainer?.visibility = GONE
+ conversationIconBadge?.visibility = GONE
expandButton?.visibility = GONE
leftIcon?.visibility = GONE
notificationProgressEndIcon?.visibility = GONE
@@ -209,6 +210,16 @@ private class AODPromotedNotificationViewUpdater(root: View) {
?.drawable
?.mutate()
?.setColorFilter(SecondaryText.colorInt, PorterDuff.Mode.SRC_IN)
+
+ if (Flags.notificationsRedesignTemplates()) {
+ (mainColumn?.layoutParams as? MarginLayoutParams)?.let { mainColumnMargins ->
+ mainColumnMargins.topMargin =
+ Notification.Builder.getContentMarginTop(
+ root.context,
+ R.dimen.notification_2025_content_margin_top,
+ )
+ }
+ }
}
fun update(content: PromotedNotificationContentModel, audiblyAlertedIconVisible: Boolean) {
@@ -229,16 +240,11 @@ private class AODPromotedNotificationViewUpdater(root: View) {
textView: ImageFloatingTextView? = null,
showOldProgress: Boolean = true,
) {
- // Icon binding must be called in this order
- updateImageView(icon, content.smallIcon)
- icon?.setImageLevel(content.iconLevel)
- icon?.setBackgroundColor(Background.colorInt)
- icon?.originalIconColor = PrimaryText.colorInt
-
updateHeader(content, hideTitle = true)
updateTitle(title, content)
updateText(textView ?: text, content)
+ updateSmallIcon(icon, content)
updateImageView(rightIcon, content.skeletonLargeIcon)
if (showOldProgress) {
@@ -341,6 +347,8 @@ private class AODPromotedNotificationViewUpdater(root: View) {
updateImageView(verificationIcon, content.verificationIcon)
updateTextView(verificationText, content.verificationText)
+
+ updateSmallIcon(conversationIcon, content)
}
private fun updateConversationHeaderDividers(
@@ -398,6 +406,19 @@ private class AODPromotedNotificationViewUpdater(root: View) {
}
}
+ private fun updateSmallIcon(
+ smallIconView: CachingIconView?,
+ content: PromotedNotificationContentModel,
+ ) {
+ smallIconView ?: return
+
+ // Icon binding must be called in this order
+ updateImageView(smallIconView, content.smallIcon)
+ smallIconView.setImageLevel(content.iconLevel)
+ smallIconView.setBackgroundColor(Background.colorInt)
+ smallIconView.originalIconColor = PrimaryText.colorInt
+ }
+
private fun inflateChronometer() {
if (chronometer != null) {
return
@@ -405,6 +426,8 @@ private class AODPromotedNotificationViewUpdater(root: View) {
chronometer = chronometerStub?.inflate() as Chronometer
chronometerStub = null
+
+ chronometer?.appendFontFeatureSetting("tnum")
}
private fun inflateOldProgressBar() {
@@ -480,14 +503,16 @@ private fun Notification.ProgressStyle.Point.toSkeleton(): Notification.Progress
}
}
-private enum class AodPromotedNotificationColor(colorUInt: UInt) {
- Background(0xFF000000u),
- PrimaryText(0xFFFFFFFFu),
- SecondaryText(0xFFCCCCCCu);
+private fun TextView.appendFontFeatureSetting(newSetting: String) {
+ fontFeatureSettings = (fontFeatureSettings?.let { "$it," } ?: "") + newSetting
+}
+
+private enum class AodPromotedNotificationColor(val colorInt: Int) {
+ Background(android.graphics.Color.BLACK),
+ PrimaryText(android.graphics.Color.WHITE),
+ SecondaryText(android.graphics.Color.WHITE);
- val colorInt = colorUInt.toInt()
- val color = Color(colorInt)
- val brush = SolidColor(color)
+ val brush = SolidColor(androidx.compose.ui.graphics.Color(colorInt))
}
private val viewUpdaterTagId = systemuiR.id.aod_promoted_notification_view_updater_tag
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt
index 0f21514fcc94..4bc685423659 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt
@@ -17,8 +17,10 @@
package com.android.systemui.statusbar.notification.promoted.domain.interactor
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style
+import com.android.systemui.util.kotlin.FlowDumperImpl
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
@@ -26,9 +28,16 @@ import kotlinx.coroutines.flow.map
@SysUISingleton
class AODPromotedNotificationInteractor
@Inject
-constructor(activeNotificationsInteractor: ActiveNotificationsInteractor) {
+constructor(
+ promotedNotificationsInteractor: PromotedNotificationsInteractor,
+ dumpManager: DumpManager,
+) : FlowDumperImpl(dumpManager) {
+ /** The content to show as the promoted notification on AOD */
val content: Flow<PromotedNotificationContentModel?> =
- activeNotificationsInteractor.topLevelRepresentativeNotifications.map { notifs ->
- notifs.firstNotNullOfOrNull { it.promotedContent }
- }
+ promotedNotificationsInteractor.topPromotedNotificationContent
+
+ val isPresent: Flow<Boolean> =
+ content
+ .map { (it != null) && (it.style != Style.Ineligible) }
+ .dumpWhileCollecting("isPresent")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt
new file mode 100644
index 000000000000..1015cfbefc41
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.promoted.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
+import com.android.systemui.statusbar.chips.notification.domain.interactor.StatusBarNotificationChipsInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+
+/**
+ * An interactor that provides details about promoted notification precedence, based on the
+ * presented order of current notification status bar chips.
+ */
+@SysUISingleton
+class PromotedNotificationsInteractor
+@Inject
+constructor(
+ activeNotificationsInteractor: ActiveNotificationsInteractor,
+ callChipInteractor: CallChipInteractor,
+ notifChipsInteractor: StatusBarNotificationChipsInteractor,
+ @Background backgroundDispatcher: CoroutineDispatcher,
+) {
+ /**
+ * This is the ordered list of notifications (and the promoted content) represented as chips in
+ * the status bar.
+ */
+ private val orderedChipNotifications: Flow<List<NotifAndPromotedContent>> =
+ combine(callChipInteractor.ongoingCallState, notifChipsInteractor.allNotificationChips) {
+ callState,
+ notifChips ->
+ buildList {
+ val callData = callState.getNotifData()?.also { add(it) }
+ addAll(
+ notifChips.mapNotNull {
+ when (it.key) {
+ callData?.key -> null // do not re-add the same call
+ else -> NotifAndPromotedContent(it.key, it.promotedContent)
+ }
+ }
+ )
+ }
+ }
+
+ private fun OngoingCallModel.getNotifData(): NotifAndPromotedContent? =
+ when (this) {
+ is OngoingCallModel.InCall -> NotifAndPromotedContent(notificationKey, promotedContent)
+ is OngoingCallModel.InCallWithVisibleApp ->
+ // TODO(b/395989259): support InCallWithVisibleApp when it has notif data
+ null
+ is OngoingCallModel.NoCall -> null
+ }
+
+ /**
+ * The top promoted notification represented by a chip, with the order determined by the order
+ * of the chips, not the notifications.
+ */
+ private val topPromotedChipNotification: Flow<PromotedNotificationContentModel?> =
+ orderedChipNotifications
+ .map { list -> list.firstNotNullOfOrNull { it.promotedContent } }
+ .distinctUntilNewInstance()
+
+ /** This is the top-most promoted notification, which should avoid regular changing. */
+ val topPromotedNotificationContent: Flow<PromotedNotificationContentModel?> =
+ combine(
+ topPromotedChipNotification,
+ activeNotificationsInteractor.topLevelRepresentativeNotifications,
+ ) { topChipNotif, topLevelNotifs ->
+ topChipNotif ?: topLevelNotifs.firstNotNullOfOrNull { it.promotedContent }
+ }
+ // #equals() can be a bit expensive on this object, but this flow will regularly try to
+ // emit the same immutable instance over and over, so just prevent that.
+ .distinctUntilNewInstance()
+
+ /**
+ * This is the ordered list of notifications (and the promoted content) represented as chips in
+ * the status bar. Flows on the background context.
+ */
+ val orderedChipNotificationKeys: Flow<List<String>> =
+ orderedChipNotifications
+ .map { list -> list.map { it.key } }
+ .distinctUntilChanged()
+ .flowOn(backgroundDispatcher)
+
+ /**
+ * Returns flow where all subsequent repetitions of the same object instance are filtered out.
+ */
+ private fun <T> Flow<T>.distinctUntilNewInstance() = distinctUntilChanged { a, b -> a === b }
+
+ /**
+ * A custom pair, but providing clearer semantic names, and implementing equality as being the
+ * same instance of the promoted content model, which allows us to use distinctUntilChanged() on
+ * flows containing this without doing pixel comparisons on the Bitmaps inside Icon objects
+ * provided by the Notification.
+ */
+ private data class NotifAndPromotedContent(
+ val key: String,
+ val promotedContent: PromotedNotificationContentModel?,
+ ) {
+ /**
+ * Define the equals of this object to only check the reference equality of the promoted
+ * content so that we can mark.
+ */
+ override fun equals(other: Any?): Boolean {
+ return when {
+ other == null -> false
+ other === this -> true
+ other !is NotifAndPromotedContent -> return false
+ else -> key == other.key && promotedContent === other.promotedContent
+ }
+ }
+
+ /** Define the hashCode to be very quick, even if it increases collisions. */
+ override fun hashCode(): Int {
+ var result = key.hashCode()
+ result = 31 * result + (promotedContent?.identity?.hashCode() ?: 0)
+ return result
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt
new file mode 100644
index 000000000000..c3b241154e0e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.content.Context
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.annotation.UiThread
+import com.android.app.tracing.coroutines.launchTraced
+import com.android.app.tracing.coroutines.withContextTraced
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.NotifInflation
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+
+@SysUISingleton
+class AsyncRowInflater
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ @Main private val mainCoroutineDispatcher: CoroutineDispatcher,
+ @NotifInflation private val inflationCoroutineDispatcher: CoroutineDispatcher,
+) {
+ /**
+ * Inflate the layout on the background thread, and invoke the listener on the main thread when
+ * finished.
+ *
+ * If the inflation fails on the background, it will be retried once on the main thread.
+ */
+ @UiThread
+ fun inflate(
+ context: Context,
+ layoutFactory: LayoutInflater.Factory2,
+ @LayoutRes resId: Int,
+ parent: ViewGroup,
+ listener: OnInflateFinishedListener,
+ ): Job {
+ val inflater = BasicRowInflater(context).apply { factory2 = layoutFactory }
+ return applicationScope.launchTraced("AsyncRowInflater-bg", inflationCoroutineDispatcher) {
+ val view =
+ try {
+ inflater.inflate(resId, parent, false)
+ } catch (ex: RuntimeException) {
+ // Probably a Looper failure, retry on the UI thread
+ Log.w(
+ "AsyncRowInflater",
+ "Failed to inflate resource in the background!" +
+ " Retrying on the UI thread",
+ ex,
+ )
+ null
+ }
+ withContextTraced("AsyncRowInflater-ui", mainCoroutineDispatcher) {
+ // If the inflate failed on the inflation thread, try again on the main thread
+ val finalView = view ?: inflater.inflate(resId, parent, false)
+ // Inform the listener of the completion
+ listener.onInflateFinished(finalView, resId, parent)
+ }
+ }
+ }
+
+ /**
+ * Callback interface (identical to the one from AsyncLayoutInflater) for receiving the inflated
+ * view
+ */
+ interface OnInflateFinishedListener {
+ @UiThread fun onInflateFinished(view: View, @LayoutRes resId: Int, parent: ViewGroup?)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt
new file mode 100644
index 000000000000..79d50b8398bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.row
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+
+/**
+ * A [LayoutInflater] that is copy of
+ * [androidx.asynclayoutinflater.view.AsyncLayoutInflater.BasicInflater]
+ */
+internal class BasicRowInflater(context: Context) : LayoutInflater(context) {
+ override fun cloneInContext(newContext: Context): LayoutInflater {
+ return BasicRowInflater(newContext)
+ }
+
+ @Throws(ClassNotFoundException::class)
+ override fun onCreateView(name: String, attrs: AttributeSet): View {
+ for (prefix in sClassPrefixList) {
+ try {
+ val view = createView(name, prefix, attrs)
+ if (view != null) {
+ return view
+ }
+ } catch (e: ClassNotFoundException) {
+ // In this case we want to let the base class take a crack at it.
+ }
+ }
+
+ return super.onCreateView(name, attrs)
+ }
+
+ companion object {
+ private val sClassPrefixList = arrayOf("android.widget.", "android.webkit.", "android.app.")
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9bf07689dbdb..1568e9e66c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -105,6 +105,7 @@ import com.android.systemui.statusbar.notification.NotificationFadeAware;
import com.android.systemui.statusbar.notification.NotificationTransitionAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.SourceType;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -120,6 +121,7 @@ import com.android.systemui.statusbar.notification.row.shared.LockscreenOtpRedac
import com.android.systemui.statusbar.notification.row.wrapper.NotificationCompactMessagingTemplateViewWrapper;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
import com.android.systemui.statusbar.notification.shared.TransparentHeaderFix;
import com.android.systemui.statusbar.notification.stack.AmbientState;
@@ -268,6 +270,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private String mLoggingKey;
private NotificationGuts mGuts;
private NotificationEntry mEntry;
+ private EntryAdapter mEntryAdapter;
private String mAppName;
private NotificationRebindingTracker mRebindingTracker;
private FalsingManager mFalsingManager;
@@ -390,11 +393,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private void toggleExpansionState(View v, boolean shouldLogExpandClickMetric) {
- if (!shouldShowPublic() && (!mIsMinimized || isExpanded())
- && mGroupMembershipManager.isGroupSummary(mEntry)) {
+ boolean isGroupRoot = NotificationBundleUi.isEnabled()
+ ? mGroupMembershipManager.isGroupRoot(mEntryAdapter)
+ : mGroupMembershipManager.isGroupSummary(mEntry);
+ if (!shouldShowPublic() && (!mIsMinimized || isExpanded()) && isGroupRoot) {
mGroupExpansionChanging = true;
- final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
- boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry);
+ final boolean wasExpanded = NotificationBundleUi.isEnabled()
+ ? mGroupExpansionManager.isGroupExpanded(mEntryAdapter)
+ : mGroupExpansionManager.isGroupExpanded(mEntry);
+ boolean nowExpanded = NotificationBundleUi.isEnabled()
+ ? mGroupExpansionManager.toggleGroupExpansion(mEntryAdapter)
+ : mGroupExpansionManager.toggleGroupExpansion(mEntry);
mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
if (shouldLogExpandClickMetric) {
mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER, nowExpanded);
@@ -910,6 +919,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mEntry;
}
+ @Nullable
+ public EntryAdapter getEntryAdapter() {
+ NotificationBundleUi.assertInNewMode();
+ return mEntryAdapter;
+ }
+
@Override
public boolean isHeadsUp() {
return mIsHeadsUp;
@@ -2010,11 +2025,25 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
*
* @param context context context of the view
* @param attrs attributes used to initialize parent view
+ * @param user the user the row is associated to
+ */
+ public ExpandableNotificationRow(Context context, AttributeSet attrs, UserHandle user) {
+ this(context, attrs, userContextForEntry(context, user));
+ NotificationBundleUi.assertInNewMode();
+ }
+
+ /**
+ * Constructs an ExpandableNotificationRow. Used by layout inflation (with a custom {@code
+ * AsyncLayoutFactory} in {@link RowInflaterTask}.
+ *
+ * @param context context context of the view
+ * @param attrs attributes used to initialize parent view
* @param entry notification that the row will be associated to (determines the user for the
* ImageResolver)
*/
public ExpandableNotificationRow(Context context, AttributeSet attrs, NotificationEntry entry) {
this(context, attrs, userContextForEntry(context, entry));
+ NotificationBundleUi.assertInLegacyMode();
}
private static Context userContextForEntry(Context base, NotificationEntry entry) {
@@ -2025,6 +2054,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
UserHandle.of(entry.getSbn().getNormalizedUserId()), /* flags= */ 0);
}
+ private static Context userContextForEntry(Context base, UserHandle user) {
+ if (base.getUserId() == user.getIdentifier()) {
+ return base;
+ }
+ return base.createContextAsUser(user, /* flags= */ 0);
+ }
+
private ExpandableNotificationRow(Context sysUiContext, AttributeSet attrs,
Context userContext) {
super(sysUiContext, attrs);
@@ -2067,7 +2103,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
IStatusBarService statusBarService,
UiEventLogger uiEventLogger,
NotificationRebindingTracker notificationRebindingTracker) {
- mEntry = entry;
+
+ if (NotificationBundleUi.isEnabled()) {
+ // TODO (b/395857098): remove when all usages are migrated
+ mEntryAdapter = entry.getEntryAdapter();
+ mEntry = entry;
+ } else {
+ mEntry = entry;
+ }
mAppName = appName;
mRebindingTracker = notificationRebindingTracker;
if (mMenuRow == null) {
@@ -2740,6 +2783,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
invalidateOutline();
mBackgroundNormal.setExpandAnimationSize(params.getWidth(), actualHeight);
+
+ if (Flags.notificationsLaunchRadius()) {
+ mBackgroundNormal.setRadius(params.getTopCornerRadius(),
+ params.getBottomCornerRadius());
+ }
}
public void setExpandAnimationRunning(boolean expandAnimationRunning) {
@@ -2871,7 +2919,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
&& !mChildrenContainer.showingAsLowPriority()) {
- final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
+ final boolean wasExpanded = isGroupExpanded();
mGroupExpansionManager.setGroupExpanded(mEntry, userExpanded);
onExpansionChanged(true /* userAction */, wasExpanded);
return;
@@ -3026,6 +3074,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public boolean isGroupExpanded() {
+ if (NotificationBundleUi.isEnabled()) {
+ return mGroupExpansionManager.isGroupExpanded(mEntryAdapter);
+ }
return mGroupExpansionManager.isGroupExpanded(mEntry);
}
@@ -3182,12 +3233,20 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
public void setSensitive(boolean sensitive, boolean hideSensitive) {
+ if (notificationsRedesignTemplates()
+ && sensitive == mSensitive && hideSensitive == mSensitiveHiddenInGeneral) {
+ return; // nothing has changed
+ }
+
int intrinsicBefore = getIntrinsicHeight();
mSensitive = sensitive;
mSensitiveHiddenInGeneral = hideSensitive;
int intrinsicAfter = getIntrinsicHeight();
if (intrinsicBefore != intrinsicAfter) {
notifyHeightChanged(/* needsAnimation= */ true);
+ } else if (notificationsRedesignTemplates()) {
+ // Just request the correct layout, even if the height hasn't changed
+ getShowingLayout().requestSelectLayout(/* needsAnimation= */ true);
}
}
@@ -3222,11 +3281,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
boolean oldShowingPublic = mShowingPublic;
mShowingPublic = mSensitive && hideSensitive;
- if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
+ boolean isShowingLayoutNotChanged = mShowingPublic == oldShowingPublic;
+ if (mShowingPublicInitialized && isShowingLayoutNotChanged) {
return;
}
- if (!animated) {
+ final boolean shouldSkipHideSensitiveAnimation =
+ Flags.skipHideSensitiveNotifAnimation() && isShowingLayoutNotChanged;
+ if (!animated || shouldSkipHideSensitiveAnimation) {
if (!NotificationContentAlphaOptimization.isEnabled()
|| mShowingPublic != oldShowingPublic) {
// Don't reset the alpha or cancel the animation if the showing layout doesn't
@@ -3761,7 +3823,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void onExpandedByGesture(boolean userExpanded) {
int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
- if (mGroupMembershipManager.isGroupSummary(mEntry)) {
+ if (NotificationBundleUi.isEnabled()
+ ? mGroupMembershipManager.isGroupRoot(mEntryAdapter)
+ : mGroupMembershipManager.isGroupSummary(mEntry)) {
event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
}
mMetricsLogger.action(event, userExpanded);
@@ -3797,7 +3861,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private void onExpansionChanged(boolean userAction, boolean wasExpanded) {
boolean nowExpanded = isExpanded();
if (mIsSummaryWithChildren && (!mIsMinimized || wasExpanded)) {
- nowExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
+ nowExpanded = isGroupExpanded();
}
// Note: nowExpanded is going to be true here on the first expansion of minimized groups,
// even though the group itself is not expanded. Use mGroupExpansionManager to get the real
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
index 6aa5e405f29c..77135802eced 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
@@ -18,243 +18,126 @@ package com.android.systemui.statusbar.notification.row
import android.animation.ValueAnimator
import android.content.Context
-import android.graphics.BlendMode
import android.graphics.Canvas
-import android.graphics.Color
import android.graphics.ColorFilter
-import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PixelFormat
+import android.graphics.drawable.Drawable
+import android.graphics.LinearGradient
+import android.graphics.Matrix
import android.graphics.Rect
-import android.graphics.RuntimeShader
+import android.graphics.RectF
import android.graphics.Shader
-import android.graphics.drawable.Drawable
-import android.widget.FrameLayout
-import androidx.compose.foundation.layout.size
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.viewinterop.AndroidView
-import com.android.internal.graphics.ColorUtils
import com.android.systemui.res.R
-import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
import com.android.wm.shell.shared.animation.Interpolators
-import kotlin.math.min
-/**
- * A background style for smarter-smart-actions. The style is composed by a simplex3d noise,
- * overlaid with sparkles.
- */
class MagicActionBackgroundDrawable(
context: Context,
- primaryContainer: Int? = null,
- seed: Float = 0f,
) : Drawable() {
- private val pixelDensity = context.resources.displayMetrics.density
- private val cornerRadius =
- context.resources.getDimensionPixelSize(R.dimen.smart_reply_button_corner_radius).toFloat()
- private val outlineStrokeWidth =
- context.resources
- .getDimensionPixelSize(R.dimen.smart_action_button_outline_stroke_width)
- .toFloat()
- private val buttonShape = Path()
- private val paddingVertical =
- context.resources.getDimensionPixelSize(R.dimen.smart_action_button_icon_padding).toFloat()
+ private val cornerRadius = context.resources.getDimension(R.dimen.magic_action_button_corner_radius)
+ private val outlineStrokeWidth = context.resources.getDimension(R.dimen.magic_action_button_outline_stroke_width)
+ private val insetVertical = 8 * context.resources.displayMetrics.density
- /** The color of the button background. */
- private val mainColor =
- primaryContainer
- ?: context.getColor(com.android.internal.R.color.materialColorPrimaryContainer)
-
- /** Slightly brighter version of [mainColor] used on the simplex noise. */
- private val effectColor: Int
- get() {
- val labColor = arrayOf(0.0, 0.0, 0.0).toDoubleArray()
- ColorUtils.colorToLAB(mainColor, labColor)
- val camColor = ColorUtils.colorToCAM(mainColor)
- return ColorUtils.CAMToColor(
- camColor.hue,
- camColor.chroma,
- min(100f, (labColor[0] + 10).toFloat()),
+ private val buttonShape = Path()
+ // Color and style
+ private val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ val bgColor =
+ context.getColor(
+ com.android.internal.R.color.materialColorPrimaryContainer
)
- }
+ color = bgColor
+ style = Paint.Style.FILL
+ }
+ private val outlinePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ val outlineColor =
+ context.getColor(
+ com.android.internal.R.color.materialColorOutlineVariant
+ )
+ color = outlineColor
+ style = Paint.Style.STROKE
+ strokeWidth = outlineStrokeWidth
+ }
+ private val outlineStartColor =
+ context.getColor(
+ com.android.internal.R.color.materialColorTertiaryContainer
+ )
+ private val outlineMiddleColor =
+ context.getColor(
+ com.android.internal.R.color.materialColorPrimaryFixedDim
+ )
+ private val outlineEndColor =
+ context.getColor(
+ com.android.internal.R.color.materialColorPrimary
+ )
+ // Animation
+ private var gradientAnimator: ValueAnimator
+ private var rotationAngle = 20f // Start rotation at 20 degrees
- private val bgShader = MagicActionBackgroundShader()
- private val bgPaint = Paint()
- private val outlinePaint = Paint()
- private val gradientAnimator =
- ValueAnimator.ofFloat(0f, 1f).apply {
- duration = 2500
- interpolator = Interpolators.LINEAR
- addUpdateListener { invalidateSelf() }
- }
- private val turbulenceAnimator =
- ValueAnimator.ofFloat(seed, seed + TURBULENCE_MOVEMENT).apply {
- duration = ANIMATION_DURATION
+ init {
+ gradientAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = 5000 // 5 seconds
interpolator = Interpolators.LINEAR
- addUpdateListener { invalidateSelf() }
+ repeatCount = 1
+ addUpdateListener { animator ->
+ val animatedValue = animator.animatedValue as Float
+ rotationAngle = 20f + animatedValue * 360f // Rotate in a spiral
+ invalidateSelf()
+ }
+ // TODO: Reset the outline color when animation ends.
start()
}
- private val effectFadeAnimation =
- ValueAnimator.ofFloat(0f, 1f).apply {
- duration = 1000
- startDelay = ANIMATION_DURATION - 1000L
- interpolator = Interpolators.STANDARD_DECELERATE
- addUpdateListener { invalidateSelf() }
- }
-
- init {
- bgShader.setColorUniform("in_color", mainColor)
- bgShader.setColorUniform("in_effectColor", effectColor)
- bgPaint.shader = bgShader
- outlinePaint.style = Paint.Style.STROKE
- // Stroke is doubled in width and then clipped, to avoid anti-aliasing artifacts at the edge
- // of the rectangle.
- outlinePaint.strokeWidth = outlineStrokeWidth * 2
- outlinePaint.blendMode = BlendMode.SCREEN
- outlinePaint.alpha = OUTLINE_ALPHA
-
- animate()
- }
-
- private fun animate() {
- turbulenceAnimator.start()
- gradientAnimator.start()
- effectFadeAnimation.start()
}
override fun draw(canvas: Canvas) {
- updateShaders()
+ val boundsF = RectF(bounds)
+ boundsF.inset(0f, insetVertical)
+ buttonShape.reset()
+ buttonShape.addRoundRect(boundsF, cornerRadius, cornerRadius, Path.Direction.CW)
- // We clip instead of drawing 2 rounded rects, otherwise there will be artifacts where
- // around the button background and the outline.
canvas.save()
+ // Draw background
canvas.clipPath(buttonShape)
canvas.drawPath(buttonShape, bgPaint)
+ // Apply gradient to outline
canvas.drawPath(buttonShape, outlinePaint)
+ updateGradient(boundsF)
canvas.restore()
}
- private fun updateShaders() {
- val effectAlpha = 1f - effectFadeAnimation.animatedValue as Float
- val turbulenceZ = turbulenceAnimator.animatedValue as Float
- bgShader.setFloatUniform("in_sparkleMove", turbulenceZ * 1000)
- bgShader.setFloatUniform("in_noiseMove", 0f, 0f, turbulenceZ)
- bgShader.setFloatUniform("in_turbulenceAlpha", effectAlpha)
- bgShader.setFloatUniform("in_spkarkleAlpha", SPARKLE_ALPHA * effectAlpha)
- val gradientOffset = gradientAnimator.animatedValue as Float * bounds.width()
- val outlineGradient =
- LinearGradient(
- gradientOffset + bounds.left.toFloat(),
- 0f,
- gradientOffset + bounds.right.toFloat(),
- 0f,
- mainColor,
- ColorUtils.setAlphaComponent(mainColor, 0),
- Shader.TileMode.MIRROR,
- )
- outlinePaint.shader = outlineGradient
+ private fun updateGradient(boundsF: RectF) {
+ val gradient = LinearGradient(
+ boundsF.left, boundsF.top,
+ boundsF.right, boundsF.bottom,
+ intArrayOf(outlineStartColor, outlineMiddleColor, outlineEndColor),
+ null,
+ Shader.TileMode.CLAMP
+ )
+ // Create a rotation matrix for the spiral effect
+ val matrix = Matrix()
+ matrix.setRotate(rotationAngle, boundsF.centerX(), boundsF.centerY())
+ gradient.setLocalMatrix(matrix)
+
+ outlinePaint.shader = gradient
}
override fun onBoundsChange(bounds: Rect) {
super.onBoundsChange(bounds)
-
- val width = bounds.width().toFloat()
- val height = bounds.height().toFloat()
- if (width == 0f || height == 0f) return
-
- bgShader.setFloatUniform("in_gridNum", NOISE_SIZE)
- bgShader.setFloatUniform("in_size", width, height)
- bgShader.setFloatUniform("in_aspectRatio", width / height)
- bgShader.setFloatUniform("in_pixelDensity", pixelDensity)
-
- buttonShape.reset()
- buttonShape.addRoundRect(
- bounds.left.toFloat(),
- bounds.top + paddingVertical,
- bounds.right.toFloat(),
- bounds.bottom - paddingVertical,
- cornerRadius,
- cornerRadius,
- Path.Direction.CW,
- )
+ invalidateSelf() // Redraw when size changes
}
override fun setAlpha(alpha: Int) {
bgPaint.alpha = alpha
+ outlinePaint.alpha = alpha
invalidateSelf()
}
override fun setColorFilter(colorFilter: ColorFilter?) {
bgPaint.colorFilter = colorFilter
+ outlinePaint.colorFilter = colorFilter
invalidateSelf()
}
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
-
- companion object {
- /** Smoothness of the turbulence. Larger numbers yield more detail. */
- private const val NOISE_SIZE = 0.57f
- /** Strength of the sparkles overlaid on the turbulence. */
- private const val SPARKLE_ALPHA = 0.15f
- /** Alpha (0..255) of the button outline */
- private const val OUTLINE_ALPHA = 82
- /** Turbulence grid size */
- private const val TURBULENCE_MOVEMENT = 4.3f
- /** Total animation duration in millis */
- private const val ANIMATION_DURATION = 5000L
- }
-}
-
-private class MagicActionBackgroundShader : RuntimeShader(SHADER) {
-
- // language=AGSL
- companion object {
- private const val UNIFORMS =
- """
- uniform float in_gridNum;
- uniform vec3 in_noiseMove;
- uniform half in_sparkleMove;
- uniform vec2 in_size;
- uniform float in_aspectRatio;
- uniform half in_pixelDensity;
- uniform float in_turbulenceAlpha;
- uniform float in_spkarkleAlpha;
- layout(color) uniform vec4 in_color;
- layout(color) uniform vec4 in_effectColor;
- """
- private const val MAIN_SHADER =
- """vec4 main(vec2 p) {
- vec2 uv = p / in_size.xy;
- uv.x *= in_aspectRatio;
- vec3 noiseP = vec3(uv + in_noiseMove.xy, in_noiseMove.z) * in_gridNum;
- half luma = getLuminosity(half3(simplex3d(noiseP)));
- half4 turbulenceColor = mix(in_color, in_effectColor, luma * in_turbulenceAlpha);
- float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_sparkleMove);
- sparkle = min(sparkle * in_spkarkleAlpha, in_spkarkleAlpha);
- return saturate(turbulenceColor + half4(sparkle));
- }
- """
- private const val SHADER = UNIFORMS + ShaderUtilLibrary.SHADER_LIB + MAIN_SHADER
- }
-}
-
-// @Preview
-@Composable
-fun DrawablePreview() {
- AndroidView(
- factory = { context ->
- FrameLayout(context).apply {
- background =
- MagicActionBackgroundDrawable(
- context = context,
- primaryContainer = Color.parseColor("#c5eae2"),
- seed = 0f,
- )
- }
- },
- modifier = Modifier.size(100.dp, 50.dp),
- )
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionButton.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionButton.kt
new file mode 100644
index 000000000000..d735360f1d4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionButton.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.Button
+
+/**
+ * Custom Button for Magic Action Button, which includes the custom background and foreground.
+ */
+@SuppressLint("AppCompatCustomView")
+class MagicActionButton @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+) : Button(context, attrs, defStyleAttr) {
+ init {
+ background = MagicActionBackgroundDrawable(context)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index e311b53bfa64..0c1dd2e026b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -56,6 +56,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NmSummarizationUiFlag;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor;
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiForceExpanded;
@@ -1457,12 +1458,12 @@ public class NotificationContentInflater implements NotificationRowContentBinder
}
@Override
- public void handleInflationException(NotificationEntry entry, Exception e) {
+ public void handleInflationException(Exception e) {
handleError(e);
}
@Override
- public void onAsyncInflationFinished(NotificationEntry entry) {
+ public void onAsyncInflationFinished() {
mEntry.onInflationTaskFinished();
mRow.onNotificationUpdated();
if (mCallback != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 430e5e4f1520..6e638f5de209 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -18,22 +18,13 @@ package com.android.systemui.statusbar.notification.row;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
-import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
-import static android.service.notification.Adjustment.KEY_TYPE;
-import static android.service.notification.NotificationAssistantService.ACTION_NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS;
-import static android.service.notification.NotificationAssistantService.EXTRA_NOTIFICATION_ADJUSTMENT;
-import static android.service.notification.NotificationAssistantService.EXTRA_NOTIFICATION_KEY;
-import android.annotation.FlaggedApi;
import android.app.INotificationManager;
import android.app.NotificationChannel;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutManager;
import android.net.Uri;
import android.os.Bundle;
@@ -41,7 +32,6 @@ import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.service.notification.NotificationAssistantService;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.IconDrawableFactory;
@@ -81,13 +71,14 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener;
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.wmshell.BubblesManager;
-import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
@@ -131,6 +122,8 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
private final Optional<BubblesManager> mBubblesManagerOptional;
private Runnable mOpenRunnable;
private final INotificationManager mNotificationManager;
+ private final AppIconProvider mAppIconProvider;
+ private final NotificationIconStyleProvider mIconStyleProvider;
private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
private final UserManager mUserManager;
@@ -154,6 +147,8 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
AccessibilityManager accessibilityManager,
HighPriorityProvider highPriorityProvider,
INotificationManager notificationManager,
+ AppIconProvider appIconProvider,
+ NotificationIconStyleProvider iconStyleProvider,
UserManager userManager,
PeopleSpaceWidgetManager peopleSpaceWidgetManager,
LauncherApps launcherApps,
@@ -180,6 +175,8 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
mAccessibilityManager = accessibilityManager;
mHighPriorityProvider = highPriorityProvider;
mNotificationManager = notificationManager;
+ mAppIconProvider = appIconProvider;
+ mIconStyleProvider = iconStyleProvider;
mUserManager = userManager;
mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
mLauncherApps = launcherApps;
@@ -427,6 +424,8 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta
notificationInfoView.bindNotification(
pmUser,
mNotificationManager,
+ mAppIconProvider,
+ mIconStyleProvider,
mOnUserInteractionCallback,
mChannelEditorDialogController,
packageName,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 49b682d0a5d2..661122510c6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import static android.app.Flags.notificationsRedesignThemedAppIcons;
import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
@@ -25,11 +26,13 @@ import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
import static android.service.notification.Adjustment.KEY_TYPE;
import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.systemui.Flags.notificationsRedesignGuts;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.Flags;
import android.app.INotificationManager;
import android.app.Notification;
@@ -70,8 +73,9 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
-import com.android.systemui.statusbar.notification.NmSummarizationUiFlag;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
import java.lang.annotation.Retention;
import java.util.List;
@@ -88,6 +92,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private TextView mAutomaticDescriptionView;
private INotificationManager mINotificationManager;
+ private AppIconProvider mAppIconProvider;
+ private NotificationIconStyleProvider mIconStyleProvider;
private OnUserInteractionCallback mOnUserInteractionCallback;
private PackageManager mPm;
private MetricsLogger mMetricsLogger;
@@ -183,6 +189,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
public void bindNotification(
PackageManager pm,
INotificationManager iNotificationManager,
+ AppIconProvider appIconProvider,
+ NotificationIconStyleProvider iconStyleProvider,
OnUserInteractionCallback onUserInteractionCallback,
ChannelEditorDialogController channelEditorDialogController,
String pkg,
@@ -200,6 +208,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
OnClickListener onCloseClick)
throws RemoteException {
mINotificationManager = iNotificationManager;
+ mAppIconProvider = appIconProvider;
+ mIconStyleProvider = iconStyleProvider;
mMetricsLogger = metricsLogger;
mOnUserInteractionCallback = onUserInteractionCallback;
mChannelEditorDialogController = channelEditorDialogController;
@@ -290,23 +300,39 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
applyAlertingBehavior(behavior, false /* userTriggered */);
}
+ @SuppressLint("WrongThread")
private void bindHeader() {
- // Package name
mPkgIcon = null;
// filled in if missing during notification inflation, which must have happened if
// we have a notification to long press on
ApplicationInfo info =
mSbn.getNotification().extras.getParcelable(EXTRA_BUILDER_APPLICATION_INFO,
ApplicationInfo.class);
- if (info != null) {
- try {
- mAppName = String.valueOf(mPm.getApplicationLabel(info));
- mPkgIcon = mPm.getApplicationIcon(info);
- } catch (Exception ignored) {}
- }
- if (mPkgIcon == null) {
- // app is gone, just show package name and generic icon
- mPkgIcon = mPm.getDefaultActivityIcon();
+ if (notificationsRedesignGuts()) {
+ if (info != null) {
+ try {
+ mAppName = String.valueOf(mPm.getApplicationLabel(info));
+ // The app icon is likely already in the cache, so let's use it
+ boolean withWorkProfileBadge =
+ mIconStyleProvider.shouldShowWorkProfileBadge(mSbn, getContext());
+ mPkgIcon = mAppIconProvider.getOrFetchAppIcon(info.packageName, getContext(),
+ withWorkProfileBadge,
+ /* themed = */ notificationsRedesignThemedAppIcons());
+ } catch (Exception ignored) {
+ }
+ }
+ } else {
+ if (info != null) {
+ try {
+ mAppName = String.valueOf(mPm.getApplicationLabel(info));
+ mPkgIcon = mPm.getApplicationIcon(info);
+ } catch (Exception ignored) {
+ }
+ }
+ if (mPkgIcon == null) {
+ // app is gone, just show package name and generic icon
+ mPkgIcon = mPm.getDefaultActivityIcon();
+ }
}
((ImageView) findViewById(R.id.pkg_icon)).setImageDrawable(mPkgIcon);
((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
index 0be1d5d9d79d..05934e7edfba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
@@ -24,6 +24,7 @@ import android.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.lang.annotation.Retention;
@@ -170,13 +171,29 @@ public interface NotificationRowContentBinder {
* @param entry notification which failed to inflate content
* @param e exception
*/
- void handleInflationException(NotificationEntry entry, Exception e);
+ default void handleInflationException(NotificationEntry entry, Exception e) {
+ handleInflationException(e);
+ }
+
+ /**
+ * Callback for when there is an inflation exception
+ *
+ * @param e exception
+ */
+ void handleInflationException(Exception e);
/**
* Callback for after the content views finish inflating.
*
* @param entry the entry with the content views set
*/
- void onAsyncInflationFinished(NotificationEntry entry);
+ default void onAsyncInflationFinished(NotificationEntry entry) {
+ onAsyncInflationFinished();
+ }
+
+ /**
+ * Callback for after the content views finish inflating.
+ */
+ void onAsyncInflationFinished();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index 517fc3a06d84..761d3fe91cd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -49,6 +49,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor
import com.android.systemui.statusbar.notification.InflationException
import com.android.systemui.statusbar.notification.NmSummarizationUiFlag
+import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
@@ -76,6 +77,7 @@ import com.android.systemui.statusbar.notification.row.shared.NotificationConten
import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor
import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer
import com.android.systemui.statusbar.policy.InflatedSmartReplyState
import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder
@@ -536,7 +538,7 @@ constructor(
val ident: String = (sbn.packageName + "/0x" + Integer.toHexString(sbn.id))
Log.e(TAG, "couldn't inflate view for notification $ident", e)
callback?.handleInflationException(
- row.entry,
+ if (NotificationBundleUi.isEnabled) entry else row.entry,
InflationException("Couldn't inflate contentViews$e"),
)
@@ -554,11 +556,11 @@ constructor(
logger.logAsyncTaskProgress(entry, "aborted")
}
- override fun handleInflationException(entry: NotificationEntry, e: Exception) {
+ override fun handleInflationException(e: Exception) {
handleError(e)
}
- override fun onAsyncInflationFinished(entry: NotificationEntry) {
+ override fun onAsyncInflationFinished() {
this.entry.onInflationTaskFinished()
row.onNotificationUpdated()
callback?.onAsyncInflationFinished(this.entry)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java
index 93b2a2d41691..6ff711deeb01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PromotedNotificationInfo.java
@@ -31,6 +31,8 @@ import com.android.internal.logging.UiEventLogger;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.icon.AppIconProvider;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
/**
* The guts of a notification revealed when performing a long press, specifically
@@ -40,6 +42,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
public class PromotedNotificationInfo extends NotificationInfo {
private static final String TAG = "PromotedNotifInfoGuts";
private INotificationManager mNotificationManager;
+ private NotificationGuts mGutsContainer;
public PromotedNotificationInfo(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -49,6 +52,8 @@ public class PromotedNotificationInfo extends NotificationInfo {
public void bindNotification(
PackageManager pm,
INotificationManager iNotificationManager,
+ AppIconProvider appIconProvider,
+ NotificationIconStyleProvider iconStyleProvider,
OnUserInteractionCallback onUserInteractionCallback,
ChannelEditorDialogController channelEditorDialogController,
String pkg,
@@ -63,40 +68,35 @@ public class PromotedNotificationInfo extends NotificationInfo {
boolean wasShownHighPriority,
AssistantFeedbackController assistantFeedbackController,
MetricsLogger metricsLogger, OnClickListener onCloseClick) throws RemoteException {
- super.bindNotification(pm, iNotificationManager, onUserInteractionCallback,
- channelEditorDialogController, pkg, notificationChannel, entry, onSettingsClick,
- onAppSettingsClick, feedbackClickListener, uiEventLogger, isDeviceProvisioned,
- isNonblockable, wasShownHighPriority, assistantFeedbackController, metricsLogger,
- onCloseClick);
+ super.bindNotification(pm, iNotificationManager, appIconProvider, iconStyleProvider,
+ onUserInteractionCallback, channelEditorDialogController, pkg, notificationChannel,
+ entry, onSettingsClick, onAppSettingsClick, feedbackClickListener, uiEventLogger,
+ isDeviceProvisioned, isNonblockable, wasShownHighPriority,
+ assistantFeedbackController, metricsLogger, onCloseClick);
mNotificationManager = iNotificationManager;
- bindDismiss(entry.getSbn(), onCloseClick);
bindDemote(entry.getSbn(), pkg);
}
-
- protected void bindDismiss(StatusBarNotification sbn,
- View.OnClickListener onCloseClick) {
- View dismissButton = findViewById(R.id.promoted_dismiss);
-
- dismissButton.setOnClickListener(onCloseClick);
- dismissButton.setVisibility(!sbn.isNonDismissable()
- && dismissButton.hasOnClickListeners() ? VISIBLE : GONE);
-
- }
-
protected void bindDemote(StatusBarNotification sbn, String packageName) {
View demoteButton = findViewById(R.id.promoted_demote);
demoteButton.setOnClickListener(getDemoteClickListener(sbn, packageName));
demoteButton.setVisibility(demoteButton.hasOnClickListeners() ? VISIBLE : GONE);
}
+ @Override
+ public void setGutsParent(NotificationGuts guts) {
+ mGutsContainer = guts;
+ super.setGutsParent(guts);
+ }
+
private OnClickListener getDemoteClickListener(StatusBarNotification sbn, String packageName) {
- return ((View unusedView) -> {
+ return ((View v) -> {
try {
// TODO(b/391661009): Signal AutomaticPromotionCoordinator here
mNotificationManager.setCanBePromoted(packageName, sbn.getUid(), false, true);
+ mGutsContainer.closeControls(v, true);
} catch (RemoteException e) {
Log.e(TAG, "Couldn't revoke live update permission", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
index 6883ec575d7e..da361406fa2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
@@ -21,10 +21,12 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon
import androidx.annotation.NonNull;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import javax.inject.Inject;
@@ -52,7 +54,7 @@ public class RowContentBindStage extends BindStage<RowContentBindParams> {
@Override
protected void executeStage(
- @NonNull NotificationEntry entry,
+ final @NonNull NotificationEntry entry,
@NonNull ExpandableNotificationRow row,
@NonNull StageCallback callback) {
RowContentBindParams params = getStageParams(entry);
@@ -77,15 +79,35 @@ public class RowContentBindStage extends BindStage<RowContentBindParams> {
InflationCallback inflationCallback = new InflationCallback() {
@Override
- public void handleInflationException(NotificationEntry entry, Exception e) {
- mNotifInflationErrorManager.setInflationError(entry, e);
+ public void handleInflationException(NotificationEntry errorEntry, Exception e) {
+ if (NotificationBundleUi.isEnabled()) {
+ mNotifInflationErrorManager.setInflationError(entry, e);
+ } else {
+ mNotifInflationErrorManager.setInflationError(errorEntry, e);
+ }
+ }
+
+ @Override
+ public void handleInflationException(Exception e) {
+
}
@Override
- public void onAsyncInflationFinished(NotificationEntry entry) {
- mNotifInflationErrorManager.clearInflationError(entry);
- getStageParams(entry).clearDirtyContentViews();
- callback.onStageFinished(entry);
+ public void onAsyncInflationFinished(NotificationEntry finishedEntry) {
+ if (NotificationBundleUi.isEnabled()) {
+ mNotifInflationErrorManager.clearInflationError(entry);
+ getStageParams(entry).clearDirtyContentViews();
+ callback.onStageFinished(entry);
+ } else {
+ mNotifInflationErrorManager.clearInflationError(finishedEntry);
+ getStageParams(finishedEntry).clearDirtyContentViews();
+ callback.onStageFinished(finishedEntry);
+ }
+ }
+
+ @Override
+ public void onAsyncInflationFinished() {
+
}
};
mBinder.cancelBind(entry, row);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
index 9f634bef4c5e..3971661fa787 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.row;
import android.content.Context;
+import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -29,9 +30,12 @@ import androidx.annotation.VisibleForTesting;
import androidx.asynclayoutinflater.view.AsyncLayoutFactory;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
+import com.android.systemui.Flags;
import com.android.systemui.res.R;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.util.time.SystemClock;
import java.util.concurrent.Executor;
@@ -41,7 +45,8 @@ import javax.inject.Inject;
/**
* An inflater task that asynchronously inflates a ExpandableNotificationRow
*/
-public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInflateFinishedListener {
+public class RowInflaterTask implements InflationTask,
+ AsyncLayoutInflater.OnInflateFinishedListener, AsyncRowInflater.OnInflateFinishedListener {
private static final String TAG = "RowInflaterTask";
private static final boolean TRACE_ORIGIN = true;
@@ -52,12 +57,17 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
private Throwable mInflateOrigin;
private final SystemClock mSystemClock;
private final RowInflaterTaskLogger mLogger;
+ private final AsyncRowInflater mAsyncRowInflater;
private long mInflateStartTimeMs;
+ private UserTracker mUserTracker;
@Inject
- public RowInflaterTask(SystemClock systemClock, RowInflaterTaskLogger logger) {
+ public RowInflaterTask(SystemClock systemClock, RowInflaterTaskLogger logger,
+ UserTracker userTracker, AsyncRowInflater asyncRowInflater) {
mSystemClock = systemClock;
mLogger = logger;
+ mUserTracker = userTracker;
+ mAsyncRowInflater = asyncRowInflater;
}
/**
@@ -81,13 +91,19 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
mInflateOrigin = new Throwable("inflate requested here");
}
mListener = listener;
- AsyncLayoutInflater inflater = new AsyncLayoutInflater(context, makeRowInflater(entry));
+ RowAsyncLayoutInflater asyncLayoutFactory = makeRowInflater(entry);
mEntry = entry;
entry.setInflationTask(this);
mLogger.logInflateStart(entry);
mInflateStartTimeMs = mSystemClock.elapsedRealtime();
- inflater.inflate(R.layout.status_bar_notification_row, parent, listenerExecutor, this);
+ if (Flags.useNotifInflationThreadForRow()) {
+ mAsyncRowInflater.inflate(context, asyncLayoutFactory,
+ R.layout.status_bar_notification_row, parent, this);
+ } else {
+ AsyncLayoutInflater inflater = new AsyncLayoutInflater(context, asyncLayoutFactory);
+ inflater.inflate(R.layout.status_bar_notification_row, parent, listenerExecutor, this);
+ }
}
/**
@@ -107,40 +123,8 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
}
private RowAsyncLayoutInflater makeRowInflater(NotificationEntry entry) {
- return new RowAsyncLayoutInflater(entry, mSystemClock, mLogger);
- }
-
- /**
- * A {@link LayoutInflater} that is copy of BasicLayoutInflater.
- */
- private static class BasicRowInflater extends LayoutInflater {
- private static final String[] sClassPrefixList =
- {"android.widget.", "android.webkit.", "android.app."};
- BasicRowInflater(Context context) {
- super(context);
- }
-
- @Override
- public LayoutInflater cloneInContext(Context newContext) {
- return new BasicRowInflater(newContext);
- }
-
- @Override
- protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
- for (String prefix : sClassPrefixList) {
- try {
- View view = createView(name, prefix, attrs);
- if (view != null) {
- return view;
- }
- } catch (ClassNotFoundException e) {
- // In this case we want to let the base class take a crack
- // at it.
- }
- }
-
- return super.onCreateView(name, attrs);
- }
+ return new RowAsyncLayoutInflater(
+ entry, mSystemClock, mLogger, mUserTracker.getUserHandle());
}
@VisibleForTesting
@@ -148,12 +132,14 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
private final NotificationEntry mEntry;
private final SystemClock mSystemClock;
private final RowInflaterTaskLogger mLogger;
+ private final UserHandle mTargetUser;
public RowAsyncLayoutInflater(NotificationEntry entry, SystemClock systemClock,
- RowInflaterTaskLogger logger) {
+ RowInflaterTaskLogger logger, UserHandle targetUser) {
mEntry = entry;
mSystemClock = systemClock;
mLogger = logger;
+ mTargetUser = targetUser;
}
@Nullable
@@ -165,8 +151,12 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
}
final long startMs = mSystemClock.elapsedRealtime();
- final ExpandableNotificationRow row =
- new ExpandableNotificationRow(context, attrs, mEntry);
+ ExpandableNotificationRow row = null;
+ if (NotificationBundleUi.isEnabled()) {
+ row = new ExpandableNotificationRow(context, attrs, mTargetUser);
+ } else {
+ row = new ExpandableNotificationRow(context, attrs, mEntry);
+ }
final long elapsedMs = mSystemClock.elapsedRealtime() - startMs;
mLogger.logCreatedRow(mEntry, elapsedMs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
index 52a0f6f92355..33d943348cb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
@@ -58,7 +58,7 @@ interface AppIconProvider {
packageName: String,
context: Context,
withWorkProfileBadge: Boolean = false,
- themed: Boolean = true,
+ themed: Boolean = false,
): Drawable
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index e9eecdd8a26f..e8affaa4b60f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -31,6 +31,7 @@ import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.DateTimeView;
+import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
@@ -41,6 +42,7 @@ import com.android.app.animation.Interpolators;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.NotificationCloseButton;
import com.android.internal.widget.NotificationExpandButton;
+import com.android.systemui.Flags;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
@@ -67,6 +69,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper imple
private CachingIconView mIcon;
private NotificationCloseButton mCloseButton;
private NotificationExpandButton mExpandButton;
+ private FrameLayout mExpandButtonSpacer;
private View mAltExpandTarget;
private View mIconContainer;
protected NotificationHeaderView mNotificationHeader;
@@ -154,6 +157,10 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper imple
mHeaderText = mView.findViewById(com.android.internal.R.id.header_text);
mAppNameText = mView.findViewById(com.android.internal.R.id.app_name_text);
mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button);
+ if (Flags.uiRichOngoingForceExpanded()) {
+ mExpandButtonSpacer =
+ mView.findViewById(com.android.internal.R.id.expand_button_spacer);
+ }
mAltExpandTarget = mView.findViewById(com.android.internal.R.id.alternate_expand_target);
mIconContainer = mView.findViewById(com.android.internal.R.id.conversation_icon_container);
mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge);
@@ -295,6 +302,9 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper imple
boolean expandable,
View.OnClickListener onClickListener,
boolean requestLayout) {
+ if (Flags.uiRichOngoingForceExpanded() && mExpandButtonSpacer != null) {
+ mExpandButtonSpacer.setVisibility(expandable ? GONE : VISIBLE);
+ }
mExpandButton.setVisibility(expandable ? VISIBLE : GONE);
mExpandButton.setOnClickListener(expandable ? onClickListener : null);
if (mAltExpandTarget != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
index 5a29a699a7e6..a507c4ceecd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
@@ -190,7 +190,8 @@ constructor(
currentMagneticListeners.forEachIndexed { i, target ->
target?.let {
if (i != currentMagneticListeners.size / 2) {
- snapBack(it, velocity)
+ val velocityMultiplier = MAGNETIC_TRANSLATION_MULTIPLIERS[i]
+ snapBack(it, velocity?.times(velocityMultiplier))
}
}
}
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 42d02e10ab8d..3ee827332877 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
@@ -52,6 +52,9 @@ import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
+import android.graphics.RenderEffect;
+import android.graphics.RenderNode;
+import android.graphics.Shader;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.Trace;
@@ -119,6 +122,7 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
import com.android.systemui.statusbar.notification.shared.NotificationHeadsUpCycling;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
@@ -513,6 +517,13 @@ public class NotificationStackScrollLayout
/** The clip path defining where we are NOT allowed to draw. */
private final Path mNegativeRoundedClipPath = new Path();
+ /** RenderNode to blur notifications which will be reused (redrawn) whenever NSSL is drawn. */
+ private final RenderNode mBlurNode = new RenderNode("BlurNode");
+
+ /** Radius of the blur effect applied to the content of the NSSL. */
+ private float mBlurRadius = 0f;
+ @Nullable private RenderEffect mBlurEffect = null;
+
/**
* The clip Path used to clip the launching notification. This may be different
* from the normal path, as the views launch animation could start clipped.
@@ -896,6 +907,7 @@ public class NotificationStackScrollLayout
mOverflingDistance = configuration.getScaledOverflingDistance();
Resources res = context.getResources();
+ mSwipeHelper.updateResourceProperties(res);
final boolean isSmallScreenLandscape = res.getBoolean(R.bool.is_small_screen_landscape);
boolean useSmallLandscapeLockscreenResources = mIsSmallLandscapeLockscreenEnabled
&& isSmallScreenLandscape;
@@ -2073,8 +2085,6 @@ public class NotificationStackScrollLayout
Resources res = getResources();
updateSplitNotificationShade();
mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
- float densityScale = res.getDisplayMetrics().density;
- mSwipeHelper.setDensityScale(densityScale);
float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
reinitView();
@@ -2949,9 +2959,13 @@ public class NotificationStackScrollLayout
}
private boolean isChildInGroup(View child) {
- return child instanceof ExpandableNotificationRow
- && mGroupMembershipManager.isChildInGroup(
- ((ExpandableNotificationRow) child).getEntry());
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow childRow = (ExpandableNotificationRow) child;
+ return NotificationBundleUi.isEnabled()
+ ? mGroupMembershipManager.isChildInGroup(childRow.getEntryAdapter())
+ : mGroupMembershipManager.isChildInGroup(childRow.getEntry());
+ }
+ return false;
}
/**
@@ -5974,6 +5988,24 @@ public class NotificationStackScrollLayout
invalidate();
}
+ @Override
+ public void setBlurRadius(float blurRadius) {
+ if (mBlurRadius != blurRadius) {
+ mBlurRadius = blurRadius;
+ updateBlurEffect();
+ invalidate();
+ }
+ }
+
+ private void updateBlurEffect() {
+ if (mBlurRadius > 0) {
+ mBlurEffect =
+ RenderEffect.createBlurEffect(mBlurRadius, mBlurRadius, Shader.TileMode.CLAMP);
+ } else {
+ mBlurEffect = null;
+ }
+ }
+
/**
* Set rounded rect clipping bounds on this view.
*/
@@ -6144,26 +6176,64 @@ public class NotificationStackScrollLayout
@Override
protected void dispatchDraw(@NonNull Canvas canvas) {
- if (!mLaunchingNotification) {
- // When launching notifications, we're clipping the children individually instead of in
- // dispatchDraw
- if (mShouldUseRoundedRectClipping) {
- // Let's clip rounded.
- canvas.clipPath(mRoundedClipPath);
+ if (mBlurEffect != null) {
+ // reuse the cached RenderNode to blur
+ mBlurNode.setPosition(0, 0, canvas.getWidth(), canvas.getHeight());
+ mBlurNode.setRenderEffect(mBlurEffect);
+ Canvas blurCanvas = mBlurNode.beginRecording();
+ // draw all the children (except HUNs) on the blurred canvas
+ super.dispatchDraw(blurCanvas);
+ mBlurNode.endRecording();
+ // apply clipping to the canvas
+ int saveCount = canvas.save();
+ applyClipToCanvas(canvas);
+ // draw the blurred content to the clipped canvas
+ canvas.drawRenderNode(mBlurNode);
+ // restore the canvas, so it doesn't clip anymore
+ canvas.restoreToCount(saveCount);
+ // draw the children that were left out during the dispatchDraw phase
+ for (int i = 0; i < getChildCount(); i++) {
+ // TODO(b/388469101) draw these children in z-order
+ ExpandableView child = getChildAtIndex(i);
+ if (shouldSkipBlurForChild(child)) {
+ super.drawChild(canvas, child, getDrawingTime());
+ }
}
- if (mShouldUseNegativeRoundedRectClipping) {
- // subtract the negative path if it is defined
- canvas.clipOutPath(mNegativeRoundedClipPath);
+ } else {
+ if (!mLaunchingNotification) {
+ // When launching notifications, we're clipping the children individually instead
+ // of in dispatchDraw
+ applyClipToCanvas(canvas);
}
+ super.dispatchDraw(canvas);
+ }
+ }
+
+ private void applyClipToCanvas(Canvas canvas) {
+ if (mShouldUseRoundedRectClipping) {
+ // clip by the positive path if it is defined
+ canvas.clipPath(mRoundedClipPath);
+ }
+ if (mShouldUseNegativeRoundedRectClipping) {
+ // subtract the negative path if it is defined
+ canvas.clipOutPath(mNegativeRoundedClipPath);
}
- super.dispatchDraw(canvas);
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean shouldUseClipping =
mShouldUseRoundedRectClipping || mShouldUseNegativeRoundedRectClipping;
- if (mLaunchingNotification && shouldUseClipping) {
+ if (mBlurEffect != null) {
+ if (shouldSkipBlurForChild(child)) {
+ // skip drawing this child during the regular dispatchDraw pass
+ return false;
+ } else {
+ // draw the child as if nothing happened, non-blurred elements shouldn't be
+ // affected by clipping either
+ return super.drawChild(canvas, child, drawingTime);
+ }
+ } else if (mLaunchingNotification && shouldUseClipping) {
// Let's clip children individually during notification launch
canvas.save();
ExpandableView expandableView = (ExpandableView) child;
@@ -6194,6 +6264,14 @@ public class NotificationStackScrollLayout
}
}
+ private boolean shouldSkipBlurForChild(View child) {
+ if (child instanceof ExpandableView row) {
+ return row.isHeadsUpState();
+ } else {
+ return false;
+ }
+ }
+
/**
* Calculate the total translation needed when dismissing.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 810d0b43b0dd..888c8cc59439 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -382,9 +382,15 @@ public class NotificationStackScrollLayoutController implements Dumpable {
// Only animate if in a non-sensitive state (not screen sharing)
boolean shouldAnimate = animate && !isSensitiveContentProtectionActive;
+ mLogger.logUpdateSensitivenessWithAnimation(shouldAnimate,
+ isSensitive,
+ isSensitiveContentProtectionActive,
+ isAnyProfilePublic);
mView.updateSensitiveness(shouldAnimate, isSensitive);
} else {
- mView.updateSensitiveness(animate, mLockscreenUserManager.isAnyProfilePublicMode());
+ boolean anyProfilePublicMode = mLockscreenUserManager.isAnyProfilePublicMode();
+ mLogger.logUpdateSensitivenessWithAnimation(animate, anyProfilePublicMode);
+ mView.updateSensitiveness(animate, anyProfilePublicMode);
}
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
index 3396306412bd..30658710c3c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
@@ -156,6 +156,44 @@ class NotificationStackScrollLogger @Inject constructor(
{ "removeTransientRow from NSSL: childKey: $str1" }
)
}
+
+ fun logUpdateSensitivenessWithAnimation(
+ shouldAnimate: Boolean,
+ isSensitive: Boolean,
+ isSensitiveContentProtectionActive: Boolean,
+ isAnyProfilePublic: Boolean,
+ ) {
+ notificationRenderBuffer.log(
+ TAG,
+ INFO,
+ {
+ bool1 = shouldAnimate
+ bool2 = isSensitive
+ bool3 = isSensitiveContentProtectionActive
+ bool4 = isAnyProfilePublic
+ },
+ {
+ "updateSensitivenessWithAnimation from NSSL: shouldAnimate=$bool1 " +
+ "isSensitive(hideSensitive)=$bool2 isSensitiveContentProtectionActive=$bool3 " +
+ "isAnyProfilePublic=$bool4"
+ },
+ )
+ }
+
+ fun logUpdateSensitivenessWithAnimation(animate: Boolean, anyProfilePublicMode: Boolean) {
+ notificationRenderBuffer.log(
+ TAG,
+ INFO,
+ {
+ bool1 = animate
+ bool2 = anyProfilePublicMode
+ },
+ {
+ "updateSensitivenessWithAnimation from NSSL: animate=$bool1 " +
+ "anyProfilePublicMode(hideSensitive)=$bool2"
+ },
+ )
+ }
}
-private const val TAG = "NotificationStackScroll" \ No newline at end of file
+private const val TAG = "NotificationStackScroll"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 6f4047f48205..c5a846e1da05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -534,12 +534,6 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
}
@Override
- public void setDensityScale(float densityScale) {
- super.setDensityScale(densityScale);
- mCallback.onDensityScaleChange(densityScale);
- }
-
- @Override
public void resetTouchState() {
super.resetTouchState();
mCallback.resetMagneticStates();
@@ -565,8 +559,6 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
*/
float getTotalTranslationLength(View animView);
- void onDensityScaleChange(float density);
-
boolean handleSwipeableViewTranslation(SwipeableView view, float translate);
// Reset any ongoing magnetic interactions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
index 5fec0965f6a0..a7305f7f27ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
@@ -58,6 +58,13 @@ interface NotificationScrollView {
*/
fun setNegativeClippingShape(shape: ShadeScrimShape?)
+ /**
+ * Sets a blur effect on the view. A radius of 0 means no blur.
+ *
+ * @param radius blur radius in pixels
+ */
+ fun setBlurRadius(radius: Float)
+
/** set the y position in px of the top of the stack in this view's coordinates */
fun setStackTop(stackTop: Float)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 6385d53dbc8b..10b665d8ef01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -25,7 +25,7 @@ import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.nano.MetricsProto
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.common.ui.view.setImportantForAccessibilityYesNo
-import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.NotifInflation
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.lifecycle.repeatWhenAttachedToWindow
import com.android.systemui.plugins.FalsingManager
@@ -76,7 +76,7 @@ import kotlinx.coroutines.flow.stateIn
class NotificationListViewBinder
@Inject
constructor(
- @Background private val backgroundDispatcher: CoroutineDispatcher,
+ @NotifInflation private val inflationDispatcher: CoroutineDispatcher,
private val hiderTracker: DisplaySwitchNotificationsHiderTracker,
@ShadeDisplayAware private val configuration: ConfigurationState,
private val falsingManager: FalsingManager,
@@ -155,7 +155,7 @@ constructor(
parentView,
attachToRoot = false,
)
- .flowOn(backgroundDispatcher)
+ .flowOn(inflationDispatcher)
.collectLatest { footerView: FooterView ->
traceAsync("bind FooterView") {
parentView.setFooterView(footerView)
@@ -240,7 +240,7 @@ constructor(
parentView,
attachToRoot = false,
)
- .flowOn(backgroundDispatcher)
+ .flowOn(inflationDispatcher)
.collectLatest { emptyShadeView: EmptyShadeView ->
traceAsync("bind EmptyShadeView") {
parentView.setEmptyShadeView(emptyShadeView)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index 43a552b516ae..a4e39cbd8388 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -94,6 +94,7 @@ constructor(
}
}
launch { viewModel.qsExpandFraction.collectTraced { view.setQsExpandFraction(it) } }
+ launch { viewModel.blurRadius(maxBlurRadius).collect(view::setBlurRadius) }
launch {
viewModel.isShowingStackOnLockscreen.collectTraced {
view.setShowingStackOnLockscreen(it)
@@ -146,6 +147,10 @@ constructor(
}
}
+ /** blur radius to be applied when the QS panel is fully expanded */
+ private val maxBlurRadius: Flow<Int> =
+ configuration.getDimensionPixelSize(R.dimen.max_shade_content_blur_radius)
+
/** flow of the scrim clipping radius */
private val scrimRadius: Flow<Int>
get() = configuration.getDimensionPixelOffset(R.dimen.notification_scrim_corner_radius)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 7f016a1cbc2e..08d98a1d53e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -15,6 +15,8 @@
*
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import com.android.compose.animation.scene.ContentKey
@@ -46,11 +48,14 @@ import com.android.systemui.util.kotlin.ActivatableFlowDumperImpl
import dagger.Lazy
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
@@ -193,6 +198,37 @@ constructor(
val qsExpandFraction: Flow<Float> =
shadeInteractor.qsExpansion.dumpWhileCollecting("qsExpandFraction")
+ /** Blur radius to be applied to Notifications. */
+ fun blurRadius(maxBlurRadius: Flow<Int>) =
+ combine(blurFraction, maxBlurRadius) { fraction, maxRadius -> fraction * maxRadius }
+
+ /**
+ * Scale of the blur effect that should be applied to Notifications.
+ *
+ * 0 -> don't blur (default, removes all blur render effects) 1 -> do the full blur (apply a
+ * render effect with the max blur radius)
+ */
+ private val blurFraction: Flow<Float> =
+ if (SceneContainerFlag.isEnabled) {
+ shadeModeInteractor.shadeMode.flatMapLatest { shadeMode ->
+ when (shadeMode) {
+ ShadeMode.Dual ->
+ combineTransform(
+ shadeInteractor.shadeExpansion,
+ shadeInteractor.qsExpansion,
+ ) { notificationShadeExpansion, qsExpansion ->
+ if (notificationShadeExpansion == 0f) {
+ // Blur out notifications as the QS overlay panel expands
+ emit(qsExpansion)
+ }
+ }
+ else -> flowOf(0f)
+ }
+ }
+ } else {
+ flowOf(0f)
+ }
+
/** Whether we should close any open notification guts. */
val shouldCloseGuts: Flow<Boolean> = stackAppearanceInteractor.shouldCloseGuts
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 04dedb629a15..9aa4c54c4292 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -275,7 +275,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
DozeScrimController dozeScrimController,
KeyguardViewMediator keyguardViewMediator,
NotificationShadeWindowController notificationShadeWindowController,
- KeyguardStateController keyguardStateController, Handler handler,
+ KeyguardStateController keyguardStateController,
+ @Main Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@Main Resources resources,
KeyguardBypassController keyguardBypassController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index b2d337797b53..66f0d4ad692e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -92,6 +92,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
+import java.util.function.Supplier;
import javax.inject.Inject;
@@ -167,6 +168,27 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
*/
@FloatRange(from = 0, to = 1)
private float mBouncerHiddenFraction = KeyguardBouncerConstants.EXPANSION_HIDDEN;
+ private boolean mIsBlurSupported = false;
+
+ private float getDefaultScrimAlpha(boolean ignoreCurrentState) {
+ if (Flags.bouncerUiRevamp() && mIsBlurSupported) {
+ // Hack to not make the shade transparent when shade blur is not enabled.
+ if (!Flags.notificationShadeBlur() && !ignoreCurrentState) {
+ // When we expand directly to full quick settings, shade state is KEYGUARD
+ if (mState == ScrimState.SHADE_LOCKED || (mState == ScrimState.KEYGUARD
+ && mQsExpansion == 1)) {
+ return BUSY_SCRIM_ALPHA;
+ }
+ }
+ return TRANSPARENT_BOUNCER_SCRIM_ALPHA;
+ } else {
+ return BUSY_SCRIM_ALPHA;
+ }
+ }
+
+ private float getDefaultScrimAlpha() {
+ return getDefaultScrimAlpha(false);
+ }
@IntDef(prefix = {"VISIBILITY_"}, value = {
TRANSPARENT,
@@ -229,7 +251,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private float mScrimBehindAlphaKeyguard = KEYGUARD_SCRIM_ALPHA;
static final float TRANSPARENT_BOUNCER_SCRIM_ALPHA = 0.54f;
- private float mDefaultScrimAlpha;
private float mRawPanelExpansionFraction;
private float mPanelScrimMinFraction;
@@ -328,7 +349,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
DozeParameters dozeParameters,
KeyguardStateController keyguardStateController,
DelayedWakeLock.Factory delayedWakeLockFactory,
- Handler handler,
+ @Main Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor,
DockManager dockManager,
ConfigurationController configurationController,
@@ -349,7 +370,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mLargeScreenShadeInterpolator = largeScreenShadeInterpolator;
mBlurConfig = blurConfig;
mWindowRootViewBlurInteractor = windowRootViewBlurInteractor;
- mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
mKeyguardStateController = keyguardStateController;
mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
@@ -410,9 +430,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
final ScrimState[] states = ScrimState.values();
for (int i = 0; i < states.length; i++) {
- states[i].init(mScrimInFront, mScrimBehind, mDozeParameters, mDockManager);
+ states[i].init(mScrimInFront, mScrimBehind, mDozeParameters, mDockManager,
+ this::isBlurCurrentlySupported);
states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
- states[i].setDefaultScrimAlpha(mDefaultScrimAlpha);
+ states[i].setDefaultScrimAlpha(getDefaultScrimAlpha());
}
mTransparentScrimBackground = notificationsScrim.getResources()
@@ -489,28 +510,39 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
Edge.Companion.create(GLANCEABLE_HUB, LOCKSCREEN)),
mGlanceableHubConsumer, mMainDispatcher);
- if (Flags.bouncerUiRevamp()) {
+ if (Flags.bouncerUiRevamp() || Flags.notificationShadeBlur()) {
collectFlow(behindScrim,
mWindowRootViewBlurInteractor.get().isBlurCurrentlySupported(),
this::handleBlurSupportedChanged);
}
}
- private void updateDefaultScrimAlpha(float alpha) {
- mDefaultScrimAlpha = alpha;
+ private void updateDefaultScrimAlphas() {
for (ScrimState state : ScrimState.values()) {
- state.setDefaultScrimAlpha(mDefaultScrimAlpha);
+ state.setDefaultScrimAlpha(getDefaultScrimAlpha(true));
}
applyAndDispatchState();
}
+ private boolean isBlurCurrentlySupported() {
+ return mWindowRootViewBlurInteractor.get()
+ .isBlurCurrentlySupported()
+ .getValue();
+ }
+
private void handleBlurSupportedChanged(boolean isBlurSupported) {
- if (isBlurSupported) {
- updateDefaultScrimAlpha(TRANSPARENT_BOUNCER_SCRIM_ALPHA);
- ScrimState.BOUNCER_SCRIMMED.setNotifBlurRadius(mBlurConfig.getMaxBlurRadiusPx());
- } else {
- ScrimState.BOUNCER_SCRIMMED.setNotifBlurRadius(0f);
- updateDefaultScrimAlpha(BUSY_SCRIM_ALPHA);
+ this.mIsBlurSupported = isBlurSupported;
+ if (Flags.bouncerUiRevamp()) {
+ updateDefaultScrimAlphas();
+ if (isBlurSupported) {
+ ScrimState.BOUNCER_SCRIMMED.setNotifBlurRadius(mBlurConfig.getMaxBlurRadiusPx());
+ } else {
+ ScrimState.BOUNCER_SCRIMMED.setNotifBlurRadius(0f);
+ }
+ }
+ if (Flags.notificationShadeBlur()) {
+ mState.prepare(mState);
+ applyAndDispatchState();
}
}
@@ -989,7 +1021,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
float behindFraction = getInterpolatedFraction();
behindFraction = (float) Math.pow(behindFraction, 0.8f);
mBehindAlpha = 1;
- mNotificationsAlpha = behindFraction * mDefaultScrimAlpha;
+ mNotificationsAlpha = behindFraction * getDefaultScrimAlpha();
} else {
if (Flags.notificationShadeBlur()) {
// TODO (b/390730594): match any spec for controlling alpha based on shade
@@ -1000,7 +1032,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mNotificationsTint = mState.getNotifTint();
} else {
mBehindAlpha = mLargeScreenShadeInterpolator.getBehindScrimAlpha(
- mPanelExpansionFraction * mDefaultScrimAlpha);
+ mPanelExpansionFraction * getDefaultScrimAlpha());
mNotificationsAlpha =
mLargeScreenShadeInterpolator.getNotificationScrimAlpha(
mPanelExpansionFraction);
@@ -1016,7 +1048,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
final float interpolatedFraction =
BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(
mBouncerHiddenFraction);
- mBehindAlpha = MathUtils.lerp(mDefaultScrimAlpha, mBehindAlpha,
+ mBehindAlpha = MathUtils.lerp(getDefaultScrimAlpha(), mBehindAlpha,
interpolatedFraction);
mBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
mBehindTint,
@@ -1106,7 +1138,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
float behindAlpha;
int behindTint = state.getBehindTint();
if (mDarkenWhileDragging) {
- behindAlpha = MathUtils.lerp(mDefaultScrimAlpha, stateBehind,
+ behindAlpha = MathUtils.lerp(getDefaultScrimAlpha(), stateBehind,
interpolatedFract);
} else {
behindAlpha = MathUtils.lerp(0 /* start */, stateBehind,
@@ -1122,7 +1154,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
}
if (mQsExpansion > 0) {
- behindAlpha = MathUtils.lerp(behindAlpha, mDefaultScrimAlpha, mQsExpansion);
+ behindAlpha = MathUtils.lerp(behindAlpha, getDefaultScrimAlpha(), mQsExpansion);
float tintProgress = mQsExpansion;
if (mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()) {
// this is case of - on lockscreen - going from expanded QS to bouncer.
@@ -1639,7 +1671,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
pw.println(mTransitionToLockScreenFullShadeNotificationsProgress);
pw.print(" mDefaultScrimAlpha=");
- pw.println(mDefaultScrimAlpha);
+ pw.println(getDefaultScrimAlpha());
pw.print(" mPanelExpansionFraction=");
pw.println(mPanelExpansionFraction);
pw.print(" mExpansionAffectsAlpha=");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 071a57a8b298..2282b9702ad5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -28,6 +28,8 @@ import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.ui.ShadeColors;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import java.util.function.Supplier;
+
import kotlinx.coroutines.ExperimentalCoroutinesApi;
/**
@@ -88,7 +90,8 @@ public enum ScrimState {
}
if (Flags.notificationShadeBlur()) {
mBehindTint = Color.TRANSPARENT;
- mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources());
+ mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources(),
+ mIsBlurSupported.get());
mBehindAlpha = 0.0f;
mNotifAlpha = 0.0f;
mFrontAlpha = 0.0f;
@@ -148,7 +151,9 @@ public enum ScrimState {
@Override
public void prepare(ScrimState previousState) {
if (Flags.bouncerUiRevamp()) {
- if (previousState == SHADE_LOCKED) {
+ // Add unlocked here because scrim state is unlocked when there is an app on top of
+ // the lockscreen and shade is pulled over it.
+ if (previousState == SHADE_LOCKED || previousState == UNLOCKED) {
mBehindAlpha = previousState.getBehindAlpha();
mNotifAlpha = previousState.getNotifAlpha();
} else {
@@ -184,12 +189,23 @@ public enum ScrimState {
@Override
public void prepare(ScrimState previousState) {
if (Flags.notificationShadeBlur()) {
- mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources());
+ mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources(),
+ mIsBlurSupported.get());
mBehindAlpha = Color.alpha(mBehindTint) / 255.0f;
- mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources());
+ mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources(),
+ mIsBlurSupported.get());
mNotifAlpha = Color.alpha(mNotifTint) / 255.0f;
mFrontAlpha = 0.0f;
} else {
+ if (Flags.bouncerUiRevamp()) {
+ // This is only required until shade blur flag is fully enabled, shade is always
+ // opaque when shade blur is not enabled, and mClipQsScrim is always false.
+ mBehindAlpha = 1f;
+ mNotifAlpha = 1f;
+ mFrontAlpha = 0f;
+ mBehindTint = mBackgroundColor;
+ return;
+ }
mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
mNotifAlpha = 1f;
mFrontAlpha = 0f;
@@ -305,9 +321,11 @@ public enum ScrimState {
mBehindTint = mBackgroundColor;
mBlankScreen = true;
} else if (Flags.notificationShadeBlur()) {
- mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources());
+ mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources(),
+ mIsBlurSupported.get());
mBehindAlpha = Color.alpha(mBehindTint) / 255.0f;
- mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources());
+ mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources(),
+ mIsBlurSupported.get());
mNotifAlpha = Color.alpha(mNotifTint) / 255.0f;
mFrontAlpha = 0.0f;
return;
@@ -400,6 +418,7 @@ public enum ScrimState {
DozeParameters mDozeParameters;
DockManager mDockManager;
boolean mDisplayRequiresBlanking;
+ protected Supplier<Boolean> mIsBlurSupported;
boolean mLaunchingAffordanceWithPreview;
boolean mOccludeAnimationPlaying;
boolean mWakeLockScreenSensorActive;
@@ -413,7 +432,7 @@ public enum ScrimState {
protected float mNotifBlurRadius = 0.0f;
public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters,
- DockManager dockManager) {
+ DockManager dockManager, Supplier<Boolean> isBlurSupported) {
mBackgroundColor = scrimBehind.getContext().getColor(R.color.shade_scrim_background_dark);
mScrimInFront = scrimInFront;
mScrimBehind = scrimBehind;
@@ -421,6 +440,7 @@ public enum ScrimState {
mDozeParameters = dozeParameters;
mDockManager = dockManager;
mDisplayRequiresBlanking = dozeParameters.getDisplayNeedsBlanking();
+ mIsBlurSupported = isBlurSupported;
}
/** Prepare state for transition. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 01de925f3d78..bc297699c41a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -46,7 +46,6 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardMessageAreaController;
import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -56,7 +55,6 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
import com.android.systemui.Flags;
import com.android.systemui.animation.back.FlingOnBackAnimationCallback;
-import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
@@ -158,7 +156,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private final ConfigurationController mConfigurationController;
private final NavigationModeController mNavigationModeController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
- private final KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
private final DreamOverlayStateController mDreamOverlayStateController;
@Nullable
private final FoldAodAnimationController mFoldAodAnimationController;
@@ -328,7 +325,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private float mQsExpansion;
final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
- private final UdfpsOverlayInteractor mUdfpsOverlayInteractor;
private final ActivityStarter mActivityStarter;
private OnDismissAction mAfterKeyguardGoneAction;
@@ -386,7 +382,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
DockManager dockManager,
NotificationShadeWindowController notificationShadeWindowController,
KeyguardStateController keyguardStateController,
- KeyguardMessageAreaController.Factory keyguardMessageAreaFactory,
Optional<SysUIUnfoldComponent> sysUIUnfoldComponent,
Lazy<ShadeController> shadeController,
LatencyTracker latencyTracker,
@@ -395,7 +390,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
PrimaryBouncerInteractor primaryBouncerInteractor,
BouncerView primaryBouncerView,
AlternateBouncerInteractor alternateBouncerInteractor,
- UdfpsOverlayInteractor udfpsOverlayInteractor,
ActivityStarter activityStarter,
KeyguardTransitionInteractor keyguardTransitionInteractor,
KeyguardDismissTransitionInteractor keyguardDismissTransitionInteractor,
@@ -423,7 +417,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mKeyguardUpdateManager = keyguardUpdateMonitor;
mStatusBarStateController = sysuiStatusBarStateController;
mDockManager = dockManager;
- mKeyguardMessageAreaFactory = keyguardMessageAreaFactory;
mShadeController = shadeController;
mLatencyTracker = latencyTracker;
mKeyguardSecurityModel = keyguardSecurityModel;
@@ -434,7 +427,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
.map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
mAlternateBouncerInteractor = alternateBouncerInteractor;
mBouncerInteractor = bouncerInteractor;
- mUdfpsOverlayInteractor = udfpsOverlayInteractor;
mActivityStarter = activityStarter;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mKeyguardDismissTransitionInteractor = keyguardDismissTransitionInteractor;
@@ -1581,6 +1573,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
&& mPrimaryBouncerView.getDelegate().dispatchBackKeyEventPreIme();
}
+ @Override
public void readyForKeyguardDone() {
mViewMediatorCallback.readyForKeyguardDone();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index ded964d8a1cc..6c8e1825ea0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -57,6 +57,7 @@ import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.settings.UserTracker;
@@ -155,7 +156,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
@Inject
StatusBarNotificationActivityStarter(
@ShadeDisplayAware Context context,
- Handler mainThreadHandler,
+ @Main Handler mainThreadHandler,
@Background Executor uiBgExecutor,
NotificationVisibilityProvider visibilityProvider,
HeadsUpManager headsUpManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 1dc9de489806..05a46cd9fa31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -54,6 +54,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.kotlin.JavaAdapter;
@@ -215,7 +216,11 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
if (ExpandHeadsUpOnInlineReply.isEnabled()) {
if (row.isChildInGroup() && !row.areChildrenExpanded()) {
// The group isn't expanded, let's make sure it's visible!
- mGroupExpansionManager.toggleGroupExpansion(row.getEntry());
+ if (NotificationBundleUi.isEnabled()) {
+ mGroupExpansionManager.toggleGroupExpansion(row.getEntryAdapter());
+ } else {
+ mGroupExpansionManager.toggleGroupExpansion(row.getEntry());
+ }
} else if (!row.isChildInGroup()) {
final boolean expandNotification;
if (row.isPinned()) {
@@ -233,7 +238,11 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
} else {
if (row.isChildInGroup() && !row.areChildrenExpanded()) {
// The group isn't expanded, let's make sure it's visible!
- mGroupExpansionManager.toggleGroupExpansion(row.getEntry());
+ if (NotificationBundleUi.isEnabled()) {
+ mGroupExpansionManager.toggleGroupExpansion(row.getEntryAdapter());
+ } else {
+ mGroupExpansionManager.toggleGroupExpansion(row.getEntry());
+ }
}
if (android.app.Flags.compactHeadsUpNotificationReply()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 76f10b1c2a8b..0d43789e95a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -20,6 +20,7 @@ import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
import com.android.systemui.DejankUtils
import com.android.systemui.Flags.lightRevealMigration
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.shade.ShadeViewController
@@ -71,7 +72,7 @@ constructor(
private val powerManager: PowerManager,
private val shadeLockscreenInteractorLazy: Lazy<ShadeLockscreenInteractor>,
private val panelExpansionInteractorLazy: Lazy<PanelExpansionInteractor>,
- private val handler: Handler = Handler(),
+ @Main private val handler: Handler,
) : WakefulnessLifecycle.Observer, ScreenOffAnimation {
private lateinit var centralSurfaces: CentralSurfaces
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt
index 8fdb6ee57587..d53cbabb1d19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt
@@ -29,7 +29,7 @@ class BatteryInteractor @Inject constructor(repo: BatteryRepository) {
val level = repo.level.filterNotNull()
/** Whether the battery has been fully charged */
- val isFull = level.map { it >= 100 }
+ val isFull = level.map { isBatteryFull(it) }
/**
* For the sake of battery views, consider it to be "charging" if plugged in. This allows users
@@ -82,6 +82,8 @@ class BatteryInteractor @Inject constructor(repo: BatteryRepository) {
companion object {
/** Level below which we consider to be critically low */
private const val CRITICAL_LEVEL = 20
+
+ fun isBatteryFull(level: Int) = level >= 100
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/icons/shared/BindableIconsRegistry.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/icons/shared/BindableIconsRegistry.kt
index 8400fb08e147..701dae1594f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/icons/shared/BindableIconsRegistry.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/icons/shared/BindableIconsRegistry.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.icons.shared
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.pipeline.icons.shared.model.BindableIcon
+import com.android.systemui.statusbar.pipeline.mobile.ui.StackedMobileBindableIcon
import com.android.systemui.statusbar.pipeline.satellite.ui.DeviceBasedSatelliteBindableIcon
import javax.inject.Inject
@@ -40,11 +41,12 @@ class BindableIconsRegistryImpl
@Inject
constructor(
/** Bindables go here */
- oemSatellite: DeviceBasedSatelliteBindableIcon
+ oemSatellite: DeviceBasedSatelliteBindableIcon,
+ stackedMobile: StackedMobileBindableIcon,
) : BindableIconsRegistry {
/**
* Adding the injected bindables to this list will get them registered with
* StatusBarIconController
*/
- override val bindableIcons: List<BindableIcon> = listOf(oemSatellite)
+ override val bindableIcons: List<BindableIcon> = listOf(oemSatellite, stackedMobile)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index ac3728d9dcaf..c52536d2b312 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -21,6 +21,7 @@ import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.flags.Flags
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -28,6 +29,7 @@ import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
@@ -39,6 +41,7 @@ import com.android.systemui.util.CarrierConfigTracker
import java.lang.ref.WeakReference
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
@@ -79,6 +82,9 @@ interface MobileIconsInteractor {
*/
val icons: StateFlow<List<MobileIconInteractor>>
+ /** Whether the mobile icons can be stacked vertically. */
+ val isStackable: StateFlow<Boolean>
+
/** True if the active mobile data subscription has data enabled */
val activeDataConnectionHasDataEnabled: StateFlow<Boolean>
@@ -126,6 +132,7 @@ interface MobileIconsInteractor {
fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor
}
+@OptIn(ExperimentalCoroutinesApi::class)
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@SysUISingleton
class MobileIconsInteractorImpl
@@ -290,6 +297,18 @@ constructor(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
+ override val isStackable =
+ if (Flags.newStatusBarIcons() && StatusBarRootModernization.isEnabled) {
+ icons.flatMapLatest { icons ->
+ combine(icons.map { it.isNonTerrestrial }) {
+ it.size == 2 && it.none { isNonTerrestrial -> isNonTerrestrial }
+ }
+ }
+ } else {
+ flowOf(false)
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
/**
* Copied from the old pipeline. We maintain a 2s period of time where we will keep the
* validated bit from the old active network (A) while data is changing to the new one (B).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
index 30cc2c5da994..abd543d78687 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.mobile.ui
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -27,7 +28,7 @@ import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collectLatest
-import com.android.app.tracing.coroutines.launchTraced as launch
+import kotlinx.coroutines.flow.combine
/**
* This class is intended to provide a context to collect on the
@@ -56,12 +57,23 @@ constructor(
// Start notifying the icon controller of subscriptions
scope.launch {
isCollecting = true
- mobileIconsViewModel.subscriptionIdsFlow.collectLatest {
- logger.logUiAdapterSubIdsSentToIconController(it)
- lastValue = it
- iconController.setNewMobileIconSubIds(it)
- shadeCarrierGroupController?.updateModernMobileIcons(it)
- }
+ combine(
+ mobileIconsViewModel.subscriptionIdsFlow,
+ mobileIconsViewModel.isStackable,
+ ::Pair,
+ )
+ .collectLatest { (subIds, isStackable) ->
+ logger.logUiAdapterSubIdsSentToIconController(subIds, isStackable)
+ lastValue = subIds
+ if (isStackable) {
+ // Passing an empty list to remove pre-existing mobile icons.
+ // StackedMobileBindableIcon will show the stacked icon instead.
+ iconController.setNewMobileIconSubIds(emptyList())
+ } else {
+ iconController.setNewMobileIconSubIds(subIds)
+ }
+ shadeCarrierGroupController?.updateModernMobileIcons(subIds)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
index 2af6795b39c4..4c2849de34ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
@@ -31,22 +31,24 @@ import javax.inject.Inject
@SysUISingleton
class MobileViewLogger
@Inject
-constructor(
- @MobileViewLog private val buffer: LogBuffer,
- dumpManager: DumpManager,
-) : Dumpable {
+constructor(@MobileViewLog private val buffer: LogBuffer, dumpManager: DumpManager) : Dumpable {
init {
dumpManager.registerNormalDumpable(this)
}
private val collectionStatuses = mutableMapOf<String, Boolean>()
- fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) {
+ fun logUiAdapterSubIdsSentToIconController(subs: List<Int>, isStackable: Boolean) {
buffer.log(
TAG,
LogLevel.INFO,
- { str1 = subs.toString() },
- { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" },
+ {
+ str1 = subs.toString()
+ bool1 = isStackable
+ },
+ {
+ "Sub IDs in MobileUiAdapter being sent to icon controller: $str1, isStackable=$bool1"
+ },
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/StackedMobileBindableIcon.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/StackedMobileBindableIcon.kt
new file mode 100644
index 000000000000..fa9fa4c1366f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/StackedMobileBindableIcon.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui
+
+import android.content.Context
+import com.android.settingslib.flags.Flags
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.core.StatusBarRootModernization
+import com.android.systemui.statusbar.pipeline.icons.shared.model.BindableIcon
+import com.android.systemui.statusbar.pipeline.icons.shared.model.ModernStatusBarViewCreator
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.StackedMobileIconBinder
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.StackedMobileIconViewModel
+import com.android.systemui.statusbar.pipeline.shared.ui.view.SingleBindableStatusBarComposeIconView
+import javax.inject.Inject
+
+@SysUISingleton
+class StackedMobileBindableIcon
+@Inject
+constructor(
+ context: Context,
+ mobileIconsViewModel: MobileIconsViewModel,
+ viewModelFactory: StackedMobileIconViewModel.Factory,
+) : BindableIcon {
+ override val slot: String =
+ context.getString(com.android.internal.R.string.status_bar_stacked_mobile)
+
+ override val initializer = ModernStatusBarViewCreator { context ->
+ SingleBindableStatusBarComposeIconView.createView(context).also { view ->
+ view.initView(slot) {
+ StackedMobileIconBinder.bind(view, mobileIconsViewModel, viewModelFactory)
+ }
+ }
+ }
+
+ override val shouldBindIcon: Boolean =
+ Flags.newStatusBarIcons() && StatusBarRootModernization.isEnabled
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index 788f041b38c0..0eef2e1ca685 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -45,6 +45,7 @@ import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarV
import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewVisibilityHelper
import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarViewBinderConstants.ALPHA_ACTIVE
import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarViewBinderConstants.ALPHA_INACTIVE
+import com.android.systemui.util.kotlin.pairwiseBy
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -131,19 +132,37 @@ object MobileIconBinder {
// Set the icon for the triangle
launch {
- viewModel.icon.distinctUntilChanged().collect { icon ->
- viewModel.verboseLogger?.logBinderReceivedSignalIcon(
- view,
- viewModel.subscriptionId,
- icon,
- )
- if (icon is SignalIconModel.Cellular) {
- iconView.setImageDrawable(mobileDrawable)
- mobileDrawable.level = icon.toSignalDrawableState()
- } else if (icon is SignalIconModel.Satellite) {
- IconViewBinder.bind(icon.icon, iconView)
+ viewModel.icon
+ .pairwiseBy(initialValue = null) { oldIcon, newIcon ->
+ // Make sure we requestLayout if the number of levels changes
+ val shouldRequestLayout =
+ when {
+ oldIcon == null -> true
+ oldIcon is SignalIconModel.Cellular &&
+ newIcon is SignalIconModel.Cellular -> {
+ oldIcon.numberOfLevels != newIcon.numberOfLevels
+ }
+ else -> false
+ }
+ Pair(shouldRequestLayout, newIcon)
+ }
+ .collect { (shouldRequestLayout, newIcon) ->
+ viewModel.verboseLogger?.logBinderReceivedSignalIcon(
+ view,
+ viewModel.subscriptionId,
+ newIcon,
+ )
+ if (newIcon is SignalIconModel.Cellular) {
+ iconView.setImageDrawable(mobileDrawable)
+ mobileDrawable.level = newIcon.toSignalDrawableState()
+ } else if (newIcon is SignalIconModel.Satellite) {
+ IconViewBinder.bind(newIcon.icon, iconView)
+ }
+
+ if (shouldRequestLayout) {
+ iconView.requestLayout()
+ }
}
- }
}
launch {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/StackedMobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/StackedMobileIconBinder.kt
new file mode 100644
index 000000000000..c9fc53ecadc0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/StackedMobileIconBinder.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.binder
+
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.StackedMobileIconViewModel
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIcon
+import com.android.systemui.statusbar.pipeline.shared.ui.view.SingleBindableStatusBarComposeIconView
+
+object StackedMobileIconBinder {
+ fun bind(
+ view: SingleBindableStatusBarComposeIconView,
+ mobileIconsViewModel: MobileIconsViewModel,
+ viewModelFactory: StackedMobileIconViewModel.Factory,
+ ): ModernStatusBarViewBinding {
+ return SingleBindableStatusBarComposeIconView.withDefaultBinding(
+ view = view,
+ shouldBeVisible = { mobileIconsViewModel.isStackable.value },
+ ) { _, tint ->
+ view.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ view.composeView.apply {
+ setViewCompositionStrategy(
+ ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
+ )
+ setContent {
+ val viewModel =
+ rememberViewModel("StackedMobileIconBinder") {
+ viewModelFactory.create()
+ }
+ if (viewModel.isIconVisible) {
+ CompositionLocalProvider(LocalContentColor provides Color(tint())) {
+ StackedMobileIcon(viewModel)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
index fd5ab135a1ad..7eda87f8418d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
@@ -19,19 +19,18 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.view
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
+import android.widget.FrameLayout
import android.widget.ImageView
-import com.android.settingslib.flags.Flags.newStatusBarIcons
import com.android.systemui.res.R
import com.android.systemui.statusbar.StatusBarIconView.getVisibleStateString
+import com.android.systemui.statusbar.core.NewStatusBarIcons
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView
-class ModernStatusBarMobileView(
- context: Context,
- attrs: AttributeSet?,
-) : ModernStatusBarView(context, attrs) {
+class ModernStatusBarMobileView(context: Context, attrs: AttributeSet?) :
+ ModernStatusBarView(context, attrs) {
var subId: Int = -1
@@ -62,15 +61,34 @@ class ModernStatusBarMobileView(
as ModernStatusBarMobileView)
.also {
// Flag-specific configuration
- if (newStatusBarIcons()) {
- // New icon (with no embedded whitespace) is slightly shorter
- // (but actually taller)
- val iconView = it.requireViewById<ImageView>(R.id.mobile_signal)
- val lp = iconView.layoutParams
- lp.height =
- context.resources.getDimensionPixelSize(
- R.dimen.status_bar_mobile_signal_size_updated
- )
+ if (NewStatusBarIcons.isEnabled) {
+ // triangle
+ it.requireViewById<ImageView>(R.id.mobile_signal).apply {
+ layoutParams.height =
+ context.resources.getDimensionPixelSize(
+ R.dimen.status_bar_mobile_signal_size_updated
+ )
+ }
+
+ // RAT indicator container
+ it.requireViewById<FrameLayout>(R.id.mobile_type_container).apply {
+ (layoutParams as MarginLayoutParams).marginEnd =
+ context.resources.getDimensionPixelSize(
+ R.dimen.status_bar_mobile_container_margin_end
+ )
+ layoutParams.height =
+ context.resources.getDimensionPixelSize(
+ R.dimen.status_bar_mobile_container_height_updated
+ )
+ }
+
+ // RAT indicator
+ it.requireViewById<ImageView>(R.id.mobile_type).apply {
+ layoutParams.height =
+ context.resources.getDimensionPixelSize(
+ R.dimen.status_bar_mobile_type_size_updated
+ )
+ }
}
it.subId = viewModel.subscriptionId
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 171e4f59b0e5..e37c3f10cfcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -23,6 +23,7 @@ import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags.NEW_NETWORK_SLICE_UI
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.res.R
+import com.android.systemui.statusbar.core.NewStatusBarIcons
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -278,10 +279,11 @@ private class CellularIconViewModel(
flowOf(null)
} else {
iconInteractor.showSliceAttribution.map {
- if (it) {
- Icon.Resource(R.drawable.mobile_network_type_background, null)
- } else {
- null
+ when {
+ it && NewStatusBarIcons.isEnabled ->
+ Icon.Resource(R.drawable.mobile_network_type_background_updated, null)
+ it -> Icon.Resource(R.drawable.mobile_network_type_background, null)
+ else -> null
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 22feb7ce77c8..6176a3e9e281 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -70,15 +70,20 @@ constructor(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
- private val firstMobileSubViewModel: StateFlow<MobileIconViewModelCommon?> =
+ val mobileSubViewModels: StateFlow<List<MobileIconViewModelCommon>> =
subscriptionIdsFlow
+ .map { ids -> ids.map { commonViewModelForSub(it) } }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
+
+ private val firstMobileSubViewModel: StateFlow<MobileIconViewModelCommon?> =
+ mobileSubViewModels
.map {
if (it.isEmpty()) {
null
} else {
// Mobile icons get reversed by [StatusBarIconController], so the last element
// in this list will show up visually first.
- commonViewModelForSub(it.last())
+ it.last()
}
}
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
@@ -94,6 +99,8 @@ constructor(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ val isStackable: StateFlow<Boolean> = interactor.isStackable
+
init {
scope.launch { subscriptionIdsFlow.collect { invalidateCaches(it) } }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModel.kt
new file mode 100644
index 000000000000..a2c2a3cd1507
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/StackedMobileIconViewModel.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class StackedMobileIconViewModel
+@AssistedInject
+constructor(mobileIconsViewModel: MobileIconsViewModel) : ExclusiveActivatable() {
+ private val hydrator = Hydrator("StackedMobileIconViewModel")
+
+ private val isStackable: Boolean by
+ hydrator.hydratedStateOf(
+ traceName = "isStackable",
+ source = mobileIconsViewModel.isStackable,
+ initialValue = false,
+ )
+
+ private val iconViewModelFlow: StateFlow<List<MobileIconViewModelCommon>> =
+ mobileIconsViewModel.mobileSubViewModels
+
+ val dualSim: DualSim? by
+ hydrator.hydratedStateOf(
+ traceName = "dualSim",
+ source =
+ iconViewModelFlow.flatMapLatest { viewModels ->
+ combine(viewModels.map { it.icon }) { icons ->
+ icons
+ .toList()
+ .filterIsInstance<SignalIconModel.Cellular>()
+ .takeIf { it.size == 2 }
+ ?.let { DualSim(it[0], it[1]) }
+ }
+ },
+ initialValue = null,
+ )
+
+ val networkTypeIcon: Icon.Resource? by
+ hydrator.hydratedStateOf(
+ traceName = "networkTypeIcon",
+ source =
+ iconViewModelFlow.flatMapLatest { viewModels ->
+ viewModels.firstOrNull()?.networkTypeIcon ?: flowOf(null)
+ },
+ initialValue = null,
+ )
+
+ val isIconVisible: Boolean by derivedStateOf { isStackable && dualSim != null }
+
+ override suspend fun onActivated(): Nothing {
+ hydrator.activate()
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): StackedMobileIconViewModel
+ }
+
+ data class DualSim(
+ val primary: SignalIconModel.Cellular,
+ val secondary: SignalIconModel.Cellular,
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt
index 9c9d41e975e3..cd320a12d577 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt
@@ -93,10 +93,11 @@ constructor(
// CollapsedStatusBarFragment doesn't need this
if (StatusBarRootModernization.isEnabled) {
- primaryChipView.isVisible = false
- systemInfoView.isVisible = false
- clockView.isVisible = false
- notificationIconsArea.isVisible = false
+ // GONE because this shouldn't take space in the layout
+ primaryChipView.hideInitially(state = View.GONE)
+ systemInfoView.hideInitially()
+ clockView.hideInitially()
+ notificationIconsArea.hideInitially()
}
view.repeatWhenAttached {
@@ -365,6 +366,17 @@ constructor(
}
}
+ /**
+ * Hide the view for initialization, but skip if it's already hidden and does not cancel
+ * animations.
+ */
+ private fun View.hideInitially(state: Int = View.INVISIBLE) {
+ if (visibility == View.INVISIBLE || visibility == View.GONE) {
+ return
+ }
+ visibility = state
+ }
+
// See CollapsedStatusBarFragment#hide.
private fun View.hide(state: Int = View.INVISIBLE, shouldAnimateChange: Boolean) {
if (visibility == View.INVISIBLE || visibility == View.GONE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StackedMobileIcon.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StackedMobileIcon.kt
new file mode 100644
index 000000000000..465a43fbfb9e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StackedMobileIcon.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.ui.composable
+
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.CornerRadius
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.android.compose.modifiers.height
+import com.android.compose.modifiers.width
+import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.StackedMobileIconViewModel
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.BarBaseHeightFiveBarsSp
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.BarBaseHeightFourBarsSp
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.BarsLevelIncrementSp
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.BarsVerticalPaddingSp
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.HorizontalPaddingFiveBarsSp
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.HorizontalPaddingFourBarsSp
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.IconHeightSp
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.IconWidthFiveBarsSp
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.IconWidthFourBarsSp
+import com.android.systemui.statusbar.pipeline.shared.ui.composable.StackedMobileIconDimensions.SecondaryBarHeightSp
+import kotlin.math.max
+
+/**
+ * The dual sim icon that shows both connections stacked vertically with the active connection on
+ * top
+ */
+@Composable
+fun StackedMobileIcon(viewModel: StackedMobileIconViewModel, modifier: Modifier = Modifier) {
+ val dualSim = viewModel.dualSim ?: return
+
+ val contentColor = LocalContentColor.current
+
+ Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) {
+ viewModel.networkTypeIcon?.let {
+ Icon(
+ it,
+ tint = contentColor,
+ modifier =
+ Modifier.height { IconHeightSp.roundToPx() }.padding(start = 1.dp, end = 2.dp),
+ )
+ }
+
+ StackedMobileIcon(dualSim, contentColor)
+ }
+}
+
+@Composable
+private fun StackedMobileIcon(
+ viewModel: StackedMobileIconViewModel.DualSim,
+ color: Color,
+ modifier: Modifier = Modifier,
+) {
+ val maxNumberOfLevels =
+ max(viewModel.primary.numberOfLevels, viewModel.secondary.numberOfLevels)
+ val dimensions = if (maxNumberOfLevels == 6) FiveBarsDimensions else FourBarsDimensions
+ val iconSize =
+ with(LocalDensity.current) { dimensions.totalWidth.toDp() to IconHeightSp.toDp() }
+
+ Canvas(modifier.size(width = iconSize.first, height = iconSize.second)) {
+ val verticalPaddingPx = BarsVerticalPaddingSp.roundToPx()
+ val horizontalPaddingPx = dimensions.barsHorizontalPadding.roundToPx()
+ val totalPaddingWidthPx = horizontalPaddingPx * (maxNumberOfLevels - 1)
+
+ val barWidthPx = (size.width - totalPaddingWidthPx) / maxNumberOfLevels
+ val dotHeightPx = SecondaryBarHeightSp.toPx()
+ val baseBarHeightPx = dimensions.barBaseHeight.toPx()
+
+ var xOffsetPx = 0f
+ for (bar in 1..maxNumberOfLevels) {
+ // Bottom dots representing secondary sim
+ val dotYOffsetPx = size.height - dotHeightPx
+ if (bar <= viewModel.secondary.numberOfLevels) {
+ drawMobileIconBar(
+ level = viewModel.secondary.level,
+ bar = bar,
+ topLeft = Offset(xOffsetPx, dotYOffsetPx),
+ size = Size(barWidthPx, dotHeightPx),
+ activeColor = color,
+ )
+ }
+
+ // Top bars representing primary sim
+ if (bar <= viewModel.primary.numberOfLevels) {
+ val barHeightPx = baseBarHeightPx + (BarsLevelIncrementSp.toPx() * (bar - 1))
+ val barYOffsetPx = dotYOffsetPx - verticalPaddingPx - barHeightPx
+ drawMobileIconBar(
+ level = viewModel.primary.level,
+ bar = bar,
+ topLeft = Offset(xOffsetPx, barYOffsetPx),
+ size = Size(barWidthPx, barHeightPx),
+ activeColor = color,
+ )
+ }
+
+ xOffsetPx += barWidthPx + horizontalPaddingPx
+ }
+ }
+}
+
+private fun DrawScope.drawMobileIconBar(
+ level: Int,
+ bar: Int,
+ topLeft: Offset,
+ size: Size,
+ activeColor: Color,
+ inactiveColor: Color = activeColor.copy(alpha = .3f),
+ cornerRadius: CornerRadius = CornerRadius(size.width / 2),
+) {
+ drawRoundRect(
+ color = if (level >= bar) activeColor else inactiveColor,
+ topLeft = topLeft,
+ size = size,
+ cornerRadius = cornerRadius,
+ )
+}
+
+private abstract class BarsDependentDimensions(
+ val totalWidth: TextUnit,
+ val barsHorizontalPadding: TextUnit,
+ val barBaseHeight: TextUnit,
+)
+
+private object FourBarsDimensions :
+ BarsDependentDimensions(
+ IconWidthFourBarsSp,
+ HorizontalPaddingFourBarsSp,
+ BarBaseHeightFourBarsSp,
+ )
+
+private object FiveBarsDimensions :
+ BarsDependentDimensions(
+ IconWidthFiveBarsSp,
+ HorizontalPaddingFiveBarsSp,
+ BarBaseHeightFiveBarsSp,
+ )
+
+private object StackedMobileIconDimensions {
+ // Common dimensions
+ val IconHeightSp = 12.sp
+ val BarsVerticalPaddingSp = 1.5.sp
+ val BarsLevelIncrementSp = 1.sp
+ val SecondaryBarHeightSp = 3.sp
+
+ // Dimensions dependant on the number of total bars
+ val IconWidthFiveBarsSp = 18.5.sp
+ val IconWidthFourBarsSp = 16.sp
+ val HorizontalPaddingFiveBarsSp = 1.5.sp
+ val HorizontalPaddingFourBarsSp = 2.sp
+ val BarBaseHeightFiveBarsSp = 3.5.sp
+ val BarBaseHeightFourBarsSp = 4.5.sp
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
index c34fa464cc3a..39a1b46292b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
@@ -41,12 +41,15 @@ import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.ui.compose.OngoingActivityChips
import com.android.systemui.statusbar.core.NewStatusBarIcons
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore
import com.android.systemui.statusbar.events.domain.interactor.SystemStatusEventAnimationInteractor
import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
import com.android.systemui.statusbar.featurepods.popups.ui.compose.StatusBarPopupChipsContainer
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.ConnectedDisplaysStatusBarNotificationIconViewStore
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
import com.android.systemui.statusbar.phone.NotificationIconContainer
import com.android.systemui.statusbar.phone.PhoneStatusBarView
import com.android.systemui.statusbar.phone.StatusBarLocation
@@ -72,6 +75,7 @@ constructor(
private val homeStatusBarViewModelFactory: HomeStatusBarViewModelFactory,
private val homeStatusBarViewBinder: HomeStatusBarViewBinder,
private val notificationIconsBinder: NotificationIconContainerStatusBarViewBinder,
+ private val iconViewStoreFactory: ConnectedDisplaysStatusBarNotificationIconViewStore.Factory,
private val darkIconManagerFactory: DarkIconManager.Factory,
private val iconController: StatusBarIconController,
private val ongoingCallController: OngoingCallController,
@@ -89,6 +93,7 @@ constructor(
statusBarViewModelFactory = homeStatusBarViewModelFactory,
statusBarViewBinder = homeStatusBarViewBinder,
notificationIconsBinder = notificationIconsBinder,
+ iconViewStoreFactory = iconViewStoreFactory,
darkIconManagerFactory = darkIconManagerFactory,
iconController = iconController,
ongoingCallController = ongoingCallController,
@@ -119,6 +124,7 @@ fun StatusBarRoot(
statusBarViewModelFactory: HomeStatusBarViewModelFactory,
statusBarViewBinder: HomeStatusBarViewBinder,
notificationIconsBinder: NotificationIconContainerStatusBarViewBinder,
+ iconViewStoreFactory: ConnectedDisplaysStatusBarNotificationIconViewStore.Factory,
darkIconManagerFactory: DarkIconManager.Factory,
iconController: StatusBarIconController,
ongoingCallController: OngoingCallController,
@@ -129,6 +135,14 @@ fun StatusBarRoot(
val displayId = parent.context.displayId
val statusBarViewModel =
rememberViewModel("HomeStatusBar") { statusBarViewModelFactory.create(displayId) }
+ val iconViewStore: NotificationIconContainerViewBinder.IconViewStore? =
+ if (StatusBarConnectedDisplays.isEnabled) {
+ rememberViewModel("HomeStatusBar.IconViewStore[$displayId]") {
+ iconViewStoreFactory.create(displayId)
+ }
+ } else {
+ null
+ }
Box(Modifier.fillMaxSize()) {
// TODO(b/364360986): remove this before rolling the flag forward
@@ -174,7 +188,10 @@ fun StatusBarRoot(
val chips by
statusBarViewModel.ongoingActivityChips
.collectAsStateWithLifecycle()
- OngoingActivityChips(chips = chips)
+ OngoingActivityChips(
+ chips = chips,
+ iconViewStore = iconViewStore,
+ )
}
}
}
@@ -238,10 +255,9 @@ fun StatusBarRoot(
)
setContent {
- val chips =
- statusBarViewModel.statusBarPopupChips
- .collectAsStateWithLifecycle()
- StatusBarPopupChipsContainer(chips = chips.value)
+ StatusBarPopupChipsContainer(
+ chips = statusBarViewModel.popupChips
+ )
}
}
endSideContent.addView(composeView, 0)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarComposeIconView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarComposeIconView.kt
new file mode 100644
index 000000000000..8076040564fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarComposeIconView.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.ui.view
+
+import android.content.Context
+import android.graphics.Color
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import androidx.compose.ui.platform.ComposeView
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewVisibilityHelper
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** Compose view that is bound to bindable_status_bar_compose_icon.xml */
+class SingleBindableStatusBarComposeIconView(context: Context, attrs: AttributeSet?) :
+ ModernStatusBarView(context, attrs) {
+
+ internal lateinit var composeView: ComposeView
+ internal lateinit var dotView: StatusBarIconView
+
+ override fun toString(): String {
+ return "SingleBindableStatusBarComposeIcon(" +
+ "slot='$slot', " +
+ "isCollecting=${binding.isCollecting()}, " +
+ "visibleState=${StatusBarIconView.getVisibleStateString(visibleState)}); " +
+ "viewString=${super.toString()}"
+ }
+
+ override fun initView(slot: String, bindingCreator: () -> ModernStatusBarViewBinding) {
+ super.initView(slot, bindingCreator)
+
+ composeView = requireViewById(R.id.compose_view)
+ dotView = requireViewById(R.id.status_bar_dot)
+ }
+
+ companion object {
+ fun createView(context: Context): SingleBindableStatusBarComposeIconView {
+ return LayoutInflater.from(context)
+ .inflate(R.layout.bindable_status_bar_compose_icon, null)
+ as SingleBindableStatusBarComposeIconView
+ }
+
+ /**
+ * Using a given binding [block], create the necessary scaffolding to handle the general
+ * case of a single status bar icon. This includes eliding into a dot view when there is not
+ * enough space, and handling tint.
+ *
+ * [block] should be a simple [launch] call that handles updating the single icon view with
+ * its new view. Currently there is no simple way to e.g., extend to handle multiple tints
+ * for dual-layered icons, and any more complex logic should probably find a way to return
+ * its own version of [ModernStatusBarViewBinding].
+ */
+ fun withDefaultBinding(
+ view: SingleBindableStatusBarComposeIconView,
+ shouldBeVisible: () -> Boolean,
+ block: suspend LifecycleOwner.(View, () -> Int) -> Unit,
+ ): ModernStatusBarViewBinding {
+ @StatusBarIconView.VisibleState
+ val visibilityState: MutableStateFlow<Int> = MutableStateFlow(STATE_HIDDEN)
+
+ val iconTint: MutableStateFlow<Int> = MutableStateFlow(Color.WHITE)
+ val decorTint: MutableStateFlow<Int> = MutableStateFlow(Color.WHITE)
+
+ var isCollecting: Boolean = false
+
+ view.repeatWhenAttached {
+ // Child binding
+ block(view) { iconTint.value }
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ // isVisible controls the visibility state of the outer group, and thus it
+ // needs to run in the CREATED lifecycle so it can continue to watch while
+ // invisible. See (b/291031862) for details
+ launch {
+ visibilityState.collect { visibilityState ->
+ // for b/296864006, we can not hide all the child views if
+ // visibilityState is STATE_HIDDEN. Because hiding all child views
+ // would cause the getWidth() of this view return 0, and that would
+ // cause the translation calculation fails in StatusIconContainer.
+ // Therefore, like class MobileIconBinder, instead of set the child
+ // views visibility to View.GONE, we set their visibility to
+ // View.INVISIBLE to make them invisible but keep the width.
+ ModernStatusBarViewVisibilityHelper.setVisibilityState(
+ visibilityState,
+ view.composeView,
+ view.dotView,
+ )
+ }
+ }
+
+ launch { iconTint.collect { tint -> view.dotView.setDecorColor(tint) } }
+
+ launch {
+ decorTint.collect { decorTint -> view.dotView.setDecorColor(decorTint) }
+ }
+
+ try {
+ awaitCancellation()
+ } finally {
+ isCollecting = false
+ }
+ }
+ }
+ }
+
+ return object : ModernStatusBarViewBinding {
+ override fun getShouldIconBeVisible(): Boolean {
+ return shouldBeVisible()
+ }
+
+ override fun onVisibilityStateChanged(state: Int) {
+ visibilityState.value = state
+ }
+
+ override fun onIconTintChanged(newTint: Int, contrastTint: Int) {
+ iconTint.value = newTint
+ }
+
+ override fun onDecorTintChanged(newTint: Int) {
+ decorTint.value = newTint
+ }
+
+ override fun isCollecting(): Boolean {
+ return isCollecting
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index f396cbfc8000..9ae2cb203d91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -20,6 +20,7 @@ import android.annotation.ColorInt
import android.graphics.Rect
import android.view.View
import androidx.compose.runtime.getValue
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -29,6 +30,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.lifecycle.Activatable
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.log.table.TableLogBufferFactory
@@ -49,6 +51,7 @@ import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
import com.android.systemui.statusbar.events.domain.interactor.SystemStatusEventAnimationInteractor
import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle
+import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.StatusBarPopupChipsViewModel
import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior
@@ -71,6 +74,8 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -94,7 +99,7 @@ import kotlinx.coroutines.flow.stateIn
* [StatusBarHideIconsForBouncerManager]. We should move those pieces of logic to this class instead
* so that it's all in one place and easily testable outside of the fragment.
*/
-interface HomeStatusBarViewModel {
+interface HomeStatusBarViewModel : Activatable {
/** Factory to create the view model for the battery icon */
val batteryViewModelFactory: BatteryViewModel.Factory
@@ -133,7 +138,7 @@ interface HomeStatusBarViewModel {
val operatorNameViewModel: StatusBarOperatorNameViewModel
/** The popup chips that should be shown on the right-hand side of the status bar. */
- val statusBarPopupChips: StateFlow<List<PopupChipModel.Shown>>
+ val popupChips: List<PopupChipModel.Shown>
/**
* True if the current scene can show the home status bar (aka this status bar), and false if
@@ -208,7 +213,7 @@ constructor(
shadeInteractor: ShadeInteractor,
shareToAppChipViewModel: ShareToAppChipViewModel,
ongoingActivityChipsViewModel: OngoingActivityChipsViewModel,
- statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel,
+ statusBarPopupChipsViewModelFactory: StatusBarPopupChipsViewModel.Factory,
animations: SystemStatusEventAnimationInteractor,
statusBarContentInsetsViewModelStore: StatusBarContentInsetsViewModelStore,
@Background bgScope: CoroutineScope,
@@ -219,6 +224,8 @@ constructor(
val tableLogger = tableLoggerFactory.getOrCreate(tableLogBufferName(thisDisplayId), 200)
+ private val statusBarPopupChips by lazy { statusBarPopupChipsViewModelFactory.create() }
+
override val isTransitioningFromLockscreenToOccluded: StateFlow<Boolean> =
keyguardTransitionInteractor
.isInTransition(Edge.create(from = LOCKSCREEN, to = OCCLUDED))
@@ -246,7 +253,8 @@ constructor(
override val ongoingActivityChipsLegacy = ongoingActivityChipsViewModel.chipsLegacy
- override val statusBarPopupChips = statusBarPopupChipsViewModel.shownPopupChips
+ override val popupChips
+ get() = statusBarPopupChips.shownPopupChips
override val isHomeStatusBarAllowedByScene: StateFlow<Boolean> =
combine(
@@ -495,7 +503,13 @@ constructor(
private fun Boolean.toVisibleOrInvisible(): Int = if (this) View.VISIBLE else View.INVISIBLE
override suspend fun onActivated(): Nothing {
- hydrator.activate()
+ coroutineScope {
+ launch { hydrator.activate() }
+ if (StatusBarPopupChips.isEnabled) {
+ launch { statusBarPopupChips.activate() }
+ }
+ awaitCancellation()
+ }
}
/** Inject this to create the display-dependent view model */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index ccd75602aa13..dd742ff8f1cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -55,6 +55,7 @@ import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.core.StatusBarRootModernization;
import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.tuner.TunerService;
@@ -216,7 +217,9 @@ public class Clock extends TextView implements
// Make sure we update to the current time
updateClock();
- updateClockVisibility();
+ if (!StatusBarRootModernization.isEnabled()) {
+ updateClockVisibility();
+ }
updateShowSeconds();
}
@@ -275,19 +278,25 @@ public class Clock extends TextView implements
@Override
public void setVisibility(int visibility) {
- if (visibility == View.VISIBLE && !shouldBeVisible()) {
- return;
+ if (!StatusBarRootModernization.isEnabled()) {
+ if (visibility == View.VISIBLE && !shouldBeVisible()) {
+ return;
+ }
}
super.setVisibility(visibility);
}
- public void setClockVisibleByUser(boolean visible) {
+ private void setClockVisibleByUser(boolean visible) {
+ StatusBarRootModernization.assertInLegacyMode();
+
mClockVisibleByUser = visible;
updateClockVisibility();
}
- public void setClockVisibilityByPolicy(boolean visible) {
+ private void setClockVisibilityByPolicy(boolean visible) {
+ StatusBarRootModernization.assertInLegacyMode();
+
mClockVisibleByPolicy = visible;
updateClockVisibility();
}
@@ -297,6 +306,8 @@ public class Clock extends TextView implements
}
private void updateClockVisibility() {
+ StatusBarRootModernization.assertInLegacyMode();
+
boolean visible = shouldBeVisible();
int visibility = visible ? View.VISIBLE : View.GONE;
super.setVisibility(visibility);
@@ -346,15 +357,23 @@ public class Clock extends TextView implements
if (CLOCK_SECONDS.equals(key)) {
mShowSeconds = TunerService.parseIntegerSwitch(newValue, false);
updateShowSeconds();
- } else if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
- setClockVisibleByUser(!StatusBarIconController.getIconHideList(getContext(), newValue)
- .contains("clock"));
- updateClockVisibility();
+ } else if (!StatusBarRootModernization.isEnabled()) {
+ if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+ setClockVisibleByUser(
+ !StatusBarIconController
+ .getIconHideList(getContext(), newValue)
+ .contains("clock"));
+ updateClockVisibility();
+ }
}
}
@Override
public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (StatusBarRootModernization.isEnabled()) {
+ return;
+ }
+
if (displayId != getDisplay().getDisplayId()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 9ad8619faacc..1d1826d532b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.policy;
import android.app.AlarmManager;
-import android.app.Flags;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -175,11 +174,7 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable {
@Override
public void setZen(int zen, Uri conditionId, String reason) {
- if (Flags.modesApi()) {
- mNoMan.setZenMode(zen, conditionId, reason, /* fromUser= */ true);
- } else {
- mNoMan.setZenMode(zen, conditionId, reason);
- }
+ mNoMan.setZenMode(zen, conditionId, reason, /* fromUser= */ true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 28cf78f6777e..9f60fe212567 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -18,8 +18,10 @@ package com.android.systemui.theme;
import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
+import static com.android.systemui.Flags.hardwareColorStyles;
import static com.android.systemui.Flags.themeOverlayControllerWakefulnessDeprecation;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
+import static com.android.systemui.monet.ColorScheme.GOOGLE_BLUE;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_HOME;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_LOCK;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_PRESET;
@@ -73,6 +75,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.KeyguardState;
@@ -99,6 +102,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -136,9 +140,11 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
private final DeviceProvisionedController mDeviceProvisionedController;
private final Resources mResources;
// Current wallpaper colors associated to a user.
- private final SparseArray<WallpaperColors> mCurrentColors = new SparseArray<>();
+ @VisibleForTesting
+ protected final SparseArray<WallpaperColors> mCurrentColors = new SparseArray<>();
private final WallpaperManager mWallpaperManager;
private final ActivityManager mActivityManager;
+ protected final SystemPropertiesHelper mSystemPropertiesHelper;
@VisibleForTesting
protected ColorScheme mColorScheme;
// If fabricated overlays were already created for the current theme.
@@ -423,7 +429,9 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
JavaAdapter javaAdapter,
KeyguardTransitionInteractor keyguardTransitionInteractor,
UiModeManager uiModeManager,
- ActivityManager activityManager) {
+ ActivityManager activityManager,
+ SystemPropertiesHelper systemPropertiesHelper
+ ) {
mContext = context;
mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET);
mIsFidelityEnabled = featureFlags.isEnabled(Flags.COLOR_FIDELITY);
@@ -443,6 +451,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mUiModeManager = uiModeManager;
mActivityManager = activityManager;
+ mSystemPropertiesHelper = systemPropertiesHelper;
dumpManager.registerDumpable(TAG, this);
Flow<Boolean> isFinishedInAsleepStateFlow = mKeyguardTransitionInteractor
@@ -498,29 +507,38 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
mUserTracker.addCallback(mUserTrackerCallback, mMainExecutor);
mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+ WallpaperColors systemColor;
+ if (hardwareColorStyles() && !mDeviceProvisionedController.isCurrentUserSetup()) {
+ Pair<Integer, Color> defaultSettings = getThemeSettingsDefaults();
+ mThemeStyle = defaultSettings.first;
+ Color seedColor = defaultSettings.second;
+
+ // we only use the first color anyway, so we can pass only the single color we have
+ systemColor = new WallpaperColors(
+ /*primaryColor*/ seedColor,
+ /*secondaryColor*/ seedColor,
+ /*tertiaryColor*/ seedColor
+ );
+ } else {
+ systemColor = mWallpaperManager.getWallpaperColors(
+ getDefaultWallpaperColorsSource(mUserTracker.getUserId()));
+ }
+
// Upon boot, make sure we have the most up to date colors
Runnable updateColors = () -> {
- WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
- getDefaultWallpaperColorsSource(mUserTracker.getUserId()));
- Runnable applyColors = () -> {
- if (DEBUG) Log.d(TAG, "Boot colors: " + systemColor);
- mCurrentColors.put(mUserTracker.getUserId(), systemColor);
- reevaluateSystemTheme(false /* forceReload */);
- };
- if (mDeviceProvisionedController.isCurrentUserSetup()) {
- mMainExecutor.execute(applyColors);
- } else {
- applyColors.run();
- }
+ if (DEBUG) Log.d(TAG, "Boot colors: " + systemColor);
+ mCurrentColors.put(mUserTracker.getUserId(), systemColor);
+ reevaluateSystemTheme(false /* forceReload */);
};
// 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()) {
- updateColors.run();
+ mMainExecutor.execute(updateColors);
} else {
mBgExecutor.execute(updateColors);
}
+
mWallpaperManager.addOnColorsChangedListener(mOnColorsChangedListener, null,
UserHandle.USER_ALL);
@@ -604,7 +622,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
@VisibleForTesting
protected boolean isPrivateProfile(UserHandle userHandle) {
- Context usercontext = mContext.createContextAsUser(userHandle,0);
+ Context usercontext = mContext.createContextAsUser(userHandle, 0);
return usercontext.getSystemService(UserManager.class).isPrivateProfile();
}
@@ -720,6 +738,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
return true;
}
+ @SuppressWarnings("StringCaseLocaleUsage") // Package name is not localized
private void updateThemeOverlays() {
final int currentUser = mUserTracker.getUserId();
final String overlayPackageJson = mSecureSettings.getStringForUser(
@@ -746,7 +765,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
OverlayIdentifier systemPalette = categoryToPackage.get(OVERLAY_CATEGORY_SYSTEM_PALETTE);
if (mIsMonetEnabled && systemPalette != null && systemPalette.getPackageName() != null) {
try {
- String colorString = systemPalette.getPackageName().toLowerCase();
+ String colorString = systemPalette.getPackageName().toLowerCase();
if (!colorString.startsWith("#")) {
colorString = "#" + colorString;
}
@@ -856,6 +875,75 @@ public class ThemeOverlayController implements CoreStartable, Dumpable {
return style;
}
+ protected Pair<Integer, String> getHardwareColorSetting() {
+ String deviceColorProperty = "ro.boot.hardware.color";
+
+ String[] themeData = mResources.getStringArray(
+ com.android.internal.R.array.theming_defaults);
+
+ // Color can be hex (`#FF0000`) or `home_wallpaper`
+ Map<String, Pair<Integer, String>> themeMap = new HashMap<>();
+
+ // extract all theme settings
+ for (String themeEntry : themeData) {
+ String[] themeComponents = themeEntry.split("\\|");
+ if (themeComponents.length != 3) continue;
+ themeMap.put(themeComponents[0],
+ new Pair<>(Style.valueOf(themeComponents[1]), themeComponents[2]));
+ }
+
+ Pair<Integer, String> fallbackTheme = themeMap.get("*");
+ if (fallbackTheme == null) {
+ Log.d(TAG, "Theming wildcard not found. Fallback to TONAL_SPOT|" + COLOR_SOURCE_HOME);
+ fallbackTheme = new Pair<>(Style.TONAL_SPOT, COLOR_SOURCE_HOME);
+ }
+
+ String deviceColorPropertyValue = mSystemPropertiesHelper.get(deviceColorProperty);
+ Pair<Integer, String> selectedTheme = themeMap.get(deviceColorPropertyValue);
+ if (selectedTheme == null) {
+ Log.d(TAG, "Sysprop `" + deviceColorProperty + "` of value '" + deviceColorPropertyValue
+ + "' not found in theming_defaults: " + Arrays.toString(themeData));
+ selectedTheme = fallbackTheme;
+ }
+
+ return selectedTheme;
+ }
+
+ @VisibleForTesting
+ protected Pair<Integer, Color> getThemeSettingsDefaults() {
+
+ Pair<Integer, String> selectedTheme = getHardwareColorSetting();
+
+ // Last fallback color
+ Color defaultSeedColor = Color.valueOf(GOOGLE_BLUE);
+
+ // defaultColor will come from wallpaper or be parsed from a string
+ boolean isWallpaper = selectedTheme.second.equals(COLOR_SOURCE_HOME);
+
+ if (isWallpaper) {
+ WallpaperColors wallpaperColors = mWallpaperManager.getWallpaperColors(
+ getDefaultWallpaperColorsSource(mUserTracker.getUserId()));
+
+ if (wallpaperColors != null) {
+ defaultSeedColor = wallpaperColors.getPrimaryColor();
+ }
+
+ Log.d(TAG, "Default seed color read from home wallpaper: " + Integer.toHexString(
+ defaultSeedColor.toArgb()));
+ } else {
+ try {
+ defaultSeedColor = Color.valueOf(Color.parseColor(selectedTheme.second));
+ Log.d(TAG, "Default seed color read from resource: " + Integer.toHexString(
+ defaultSeedColor.toArgb()));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Error parsing color: " + selectedTheme.second, e);
+ // defaultSeedColor remains unchanged in this case
+ }
+ }
+
+ return new Pair<>(selectedTheme.first, defaultSeedColor);
+ }
+
@Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("mSystemColors=" + mCurrentColors);
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
index 70774f13fe6b..c43e7637998c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
@@ -65,15 +65,6 @@ public abstract class GlobalConcurrencyModule {
}
/**
- * @deprecated Use @Main Handler.
- */
- @Deprecated
- @Provides
- public static Handler provideHandler() {
- return new Handler();
- }
-
- /**
* Provide an Executor specifically for running UI operations on a separate thread.
*
* Keep submitted runnables short and to the point, just as with any other UI code.
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.kt b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.kt
index a7abb6b5f1d3..5b5f85c12efc 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.kt
@@ -53,6 +53,14 @@ object SysUIConcurrencyModule {
private const val NOTIFICATION_INFLATION_SLOW_DISPATCH_THRESHOLD = 1000L
private const val NOTIFICATION_INFLATION_SLOW_DELIVERY_THRESHOLD = 1000L
+ /**
+ * Choreographer instance for the main thread.
+ * TODO(b/395887935): Lets move this to @Main and provide thread-local references
+ */
+ @Provides
+ @SysUISingleton
+ fun providesChoreographer(): Choreographer = Choreographer.getInstance()
+
/** Background Looper */
@Provides
@SysUISingleton
@@ -99,10 +107,7 @@ object SysUIConcurrencyModule {
@Provides
@SysUISingleton
@NotifInflation
- fun provideNotifInflationLooper(@Background bgLooper: Looper): Looper {
- if (!Flags.dedicatedNotifInflationThread()) {
- return bgLooper
- }
+ fun provideNotifInflationLooper(): Looper {
val thread = HandlerThread("NotifInflation", Process.THREAD_PRIORITY_BACKGROUND)
thread.start()
val looper = thread.getLooper()
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
index e5c1e7daa25a..79ff38eabc08 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -21,6 +21,7 @@ import com.android.systemui.coroutines.newTracingContext
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.NotifInflation
import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.util.settings.SettingsSingleThreadBackground
import dagger.Module
@@ -123,4 +124,19 @@ class SysUICoroutinesModule {
): CoroutineContext {
return uiBgCoroutineDispatcher
}
+
+ /** Coroutine dispatcher for background notification inflation. */
+ @Provides
+ @NotifInflation
+ @SysUISingleton
+ fun notifInflationCoroutineDispatcher(
+ @NotifInflation notifInflationExecutor: Executor,
+ @Background bgCoroutineDispatcher: CoroutineDispatcher,
+ ): CoroutineDispatcher {
+ if (com.android.systemui.Flags.useNotifInflationThreadForFooter()) {
+ return notifInflationExecutor.asCoroutineDispatcher()
+ } else {
+ return bgCoroutineDispatcher
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/repository/SecureSettingsForUserRepository.kt b/packages/SystemUI/src/com/android/systemui/util/settings/repository/SecureSettingsForUserRepository.kt
new file mode 100644
index 000000000000..4d6eb4d8f391
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/repository/SecureSettingsForUserRepository.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.settings.repository
+
+import android.provider.Settings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.settings.SecureSettings
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineDispatcher
+
+/** Repository observing values of a [Settings.Secure] for the specified user. */
+@SysUISingleton
+class SecureSettingsForUserRepository
+@Inject
+constructor(
+ secureSettings: SecureSettings,
+ @Background backgroundDispatcher: CoroutineDispatcher,
+ @Background backgroundContext: CoroutineContext,
+) : SettingsForUserRepository(secureSettings, backgroundDispatcher, backgroundContext)
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/repository/SettingsForUserRepository.kt b/packages/SystemUI/src/com/android/systemui/util/settings/repository/SettingsForUserRepository.kt
new file mode 100644
index 000000000000..94b3fd244a92
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/repository/SettingsForUserRepository.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.settings.repository
+
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import com.android.systemui.util.settings.UserSettingsProxy
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
+
+/**
+ * Repository observing values of a [UserSettingsProxy] for the specified user. This repository
+ * should be used for any system that tracks the desired user internally (e.g. the Quick Settings
+ * tiles system). In other cases, use a [UserAwareSettingsRepository] instead.
+ */
+abstract class SettingsForUserRepository(
+ private val userSettings: UserSettingsProxy,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ @Background private val backgroundContext: CoroutineContext,
+) {
+ fun boolSettingForUser(
+ userId: Int,
+ name: String,
+ defaultValue: Boolean = false,
+ ): Flow<Boolean> =
+ settingObserver(name, userId) { userSettings.getBoolForUser(name, defaultValue, userId) }
+ .distinctUntilChanged()
+ .flowOn(backgroundDispatcher)
+
+ fun <T> settingObserver(name: String, userId: Int, settingsReader: () -> T): Flow<T> {
+ return userSettings
+ .observerFlow(userId, name)
+ .onStart { emit(Unit) }
+ .map { settingsReader.invoke() }
+ }
+
+ suspend fun setBoolForUser(userId: Int, name: String, value: Boolean) {
+ withContext(backgroundContext) { userSettings.putBoolForUser(name, value, userId) }
+ }
+
+ suspend fun getBoolForUser(userId: Int, name: String, defaultValue: Boolean = false): Boolean {
+ return withContext(backgroundContext) {
+ userSettings.getBoolForUser(name, defaultValue, userId)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt
index 73329b467c04..a8068cda685b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt
@@ -33,7 +33,8 @@ import kotlinx.coroutines.withContext
/**
* Repository for observing values of a [UserSettingsProxy], for the currently active user. That
* means that when the user is switched and the new user has a different value, the flow will emit
- * the new value.
+ * the new value. For any system that tracks the desired user internally (e.g. the Quick Settings
+ * tiles system), use a [SettingsForUserRepository] instead.
*/
// TODO: b/377244768 - Make internal when UserAwareSecureSettingsRepository can be made internal.
abstract class UserAwareSettingsRepository(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index ae3756d390af..6fc95610159a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -308,9 +308,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
private int mWindowGravity;
@VisibleForTesting
- final int mVolumeRingerIconDrawableId = R.drawable.ic_speaker_on;
+ final int mVolumeRingerIconDrawableId = R.drawable.ic_legacy_speaker_on;
@VisibleForTesting
- final int mVolumeRingerMuteIconDrawableId = R.drawable.ic_speaker_mute;
+ final int mVolumeRingerMuteIconDrawableId = R.drawable.ic_legacy_speaker_mute;
private int mOriginalGravity;
private final DevicePostureController.Callback mDevicePostureControllerCallback;
@@ -1791,8 +1791,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
enableRingerViewsH(!isZenMuted);
switch (mState.ringerModeInternal) {
case AudioManager.RINGER_MODE_VIBRATE:
- mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
- mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
+ mRingerIcon.setImageResource(R.drawable.ic_legacy_volume_ringer_vibrate);
+ mSelectedRingerIcon.setImageResource(
+ R.drawable.ic_legacy_volume_ringer_vibrate);
addAccessibilityDescription(mRingerIcon, RINGER_MODE_VIBRATE,
mContext.getString(R.string.volume_ringer_hint_mute));
mRingerIcon.setTag(Events.ICON_STATE_VIBRATE);
@@ -1990,7 +1991,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
if (zenMuted) {
iconRes = com.android.internal.R.drawable.ic_qs_dnd;
} else if (isRingVibrate) {
- iconRes = R.drawable.ic_volume_ringer_vibrate;
+ iconRes = R.drawable.ic_legacy_volume_ringer_vibrate;
} else if (isRingSilent) {
iconRes = row.iconMuteRes;
} else if (ss.routedToBluetooth) {
@@ -2009,7 +2010,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
row.setIcon(iconRes, mContext.getTheme());
row.iconState =
- iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
+ iconRes == R.drawable.ic_legacy_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
: (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes)
? Events.ICON_STATE_MUTE
: (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
index 025e269b70b6..7b08317d5265 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
@@ -18,8 +18,13 @@ package com.android.systemui.volume.dialog.dagger.module
import com.android.systemui.volume.dialog.ringer.data.repository.VolumeDialogRingerFeedbackRepository
import com.android.systemui.volume.dialog.ringer.data.repository.VolumeDialogRingerFeedbackRepositoryImpl
+import com.android.systemui.volume.dialog.ringer.ui.binder.VolumeDialogRingerViewBinder
+import com.android.systemui.volume.dialog.settings.ui.binder.VolumeDialogSettingsButtonViewBinder
+import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSlidersViewBinder
+import com.android.systemui.volume.dialog.ui.binder.ViewBinder
import dagger.Binds
import dagger.Module
+import dagger.Provides
/** Dagger module for volume dialog code in the volume package */
@Module
@@ -29,4 +34,14 @@ interface VolumeDialogModule {
fun bindVolumeDialogRingerFeedbackRepository(
ringerFeedbackRepository: VolumeDialogRingerFeedbackRepositoryImpl
): VolumeDialogRingerFeedbackRepository
+
+ companion object {
+
+ @Provides
+ fun provideViewBinders(
+ slidersViewBinder: VolumeDialogSlidersViewBinder,
+ ringerViewBinder: VolumeDialogRingerViewBinder,
+ settingsButtonViewBinder: VolumeDialogSettingsButtonViewBinder,
+ ): List<ViewBinder> = listOf(slidersViewBinder, ringerViewBinder, settingsButtonViewBinder)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
index eb2b2f68a6e2..ef750574830a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
@@ -39,6 +39,7 @@ import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerDrawerState
import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerViewModel
import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerViewModelState
import com.android.systemui.volume.dialog.ringer.ui.viewmodel.VolumeDialogRingerDrawerViewModel
+import com.android.systemui.volume.dialog.ui.binder.ViewBinder
import com.android.systemui.volume.dialog.ui.utils.suspendAnimate
import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel
import javax.inject.Inject
@@ -60,7 +61,7 @@ class VolumeDialogRingerViewBinder
constructor(
private val viewModel: VolumeDialogRingerDrawerViewModel,
private val dialogViewModel: VolumeDialogViewModel,
-) {
+) : ViewBinder {
private val roundnessSpringForce =
SpringForce(1F).apply {
stiffness = 800F
@@ -73,10 +74,11 @@ constructor(
}
private val rgbEvaluator = ArgbEvaluator()
- fun CoroutineScope.bind(view: View) {
+ override fun CoroutineScope.bind(view: View) {
val volumeDialogBackgroundView = view.requireViewById<View>(R.id.volume_dialog_background)
val ringerBackgroundView = view.requireViewById<View>(R.id.ringer_buttons_background)
val drawerContainer = view.requireViewById<MotionLayout>(R.id.volume_ringer_drawer)
+
val unselectedButtonUiModel = RingerButtonUiModel.getUnselectedButton(view.context)
val selectedButtonUiModel = RingerButtonUiModel.getSelectedButton(view.context)
val volumeDialogBgSmallRadius =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
index a330685fc6bb..54f04e274c03 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
@@ -21,6 +21,7 @@ import android.widget.ImageButton
import com.android.systemui.res.R
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
import com.android.systemui.volume.dialog.settings.ui.viewmodel.VolumeDialogSettingsButtonViewModel
+import com.android.systemui.volume.dialog.ui.binder.ViewBinder
import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -34,9 +35,9 @@ class VolumeDialogSettingsButtonViewBinder
constructor(
private val viewModel: VolumeDialogSettingsButtonViewModel,
private val dialogViewModel: VolumeDialogViewModel,
-) {
+) : ViewBinder {
- fun CoroutineScope.bind(view: View) {
+ override fun CoroutineScope.bind(view: View) {
val button = view.requireViewById<ImageButton>(R.id.volume_dialog_settings)
launch { dialogViewModel.addTouchableBounds(button) }
viewModel.isVisible
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
index 7f58c835094f..0d970e5117c2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
@@ -25,6 +25,7 @@ import com.android.systemui.res.R
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSlidersViewModel
+import com.android.systemui.volume.dialog.ui.binder.ViewBinder
import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -38,16 +39,16 @@ class VolumeDialogSlidersViewBinder
constructor(
private val viewModel: VolumeDialogSlidersViewModel,
private val dialogViewModel: VolumeDialogViewModel,
-) {
+) : ViewBinder {
- fun CoroutineScope.bind(view: View) {
+ override fun CoroutineScope.bind(view: View) {
val floatingSlidersContainer: ViewGroup =
view.requireViewById(R.id.volume_dialog_floating_sliders_container)
val mainSliderContainer: View =
view.requireViewById(R.id.volume_dialog_main_slider_container)
val background: View = view.requireViewById(R.id.volume_dialog_background)
- val settingsButton: View = view.requireViewById(R.id.volume_dialog_settings)
- val ringerDrawer: View = view.requireViewById(R.id.volume_ringer_drawer)
+ val bottomSection: View = view.requireViewById(R.id.volume_dialog_bottom_section_container)
+ val topSection: View = view.requireViewById(R.id.volume_dialog_top_section_container)
launch { dialogViewModel.addTouchableBounds(mainSliderContainer, floatingSlidersContainer) }
viewModel.sliders
@@ -55,7 +56,7 @@ constructor(
bindSlider(
uiModel.sliderComponent,
mainSliderContainer,
- arrayOf(mainSliderContainer, background, settingsButton, ringerDrawer),
+ arrayOf(mainSliderContainer, background, bottomSection, topSection),
)
val floatingSliderViewBinders = uiModel.floatingSliderComponent
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/ViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/ViewBinder.kt
new file mode 100644
index 000000000000..4d1af0d71108
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/ViewBinder.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.dialog.ui.binder
+
+import android.view.View
+import kotlinx.coroutines.CoroutineScope
+
+interface ViewBinder {
+
+ fun CoroutineScope.bind(view: View)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
index 7cc4bcc4e11c..98042d5022f9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
@@ -17,28 +17,28 @@
package com.android.systemui.volume.dialog.ui.binder
import android.app.Dialog
-import android.content.res.Resources
import android.view.View
import android.view.ViewTreeObserver
import android.view.WindowInsets
+import androidx.compose.ui.util.lerp
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.core.view.updatePadding
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.FloatValueHolder
+import androidx.dynamicanimation.animation.SpringAnimation
+import androidx.dynamicanimation.animation.SpringForce
import com.android.internal.view.RotationPolicy
import com.android.systemui.common.ui.view.onApplyWindowInsets
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.res.R
import com.android.systemui.util.kotlin.awaitCancellationThenDispose
-import com.android.systemui.volume.SystemUIInterpolators
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
-import com.android.systemui.volume.dialog.ringer.ui.binder.VolumeDialogRingerViewBinder
-import com.android.systemui.volume.dialog.settings.ui.binder.VolumeDialogSettingsButtonViewBinder
import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
-import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSlidersViewBinder
import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory
import com.android.systemui.volume.dialog.ui.utils.suspendAnimate
import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel
import com.android.systemui.volume.dialog.utils.VolumeTracer
import javax.inject.Inject
+import kotlin.math.ceil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -50,26 +50,25 @@ import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
+private const val SPRING_STIFFNESS = 700f
+private const val SPRING_DAMPING_RATIO = 0.9f
+
+private const val FRACTION_HIDE = 0f
+private const val FRACTION_SHOW = 1f
+private const val ANIMATION_MINIMUM_VISIBLE_CHANGE = 0.01f
+
/** Binds the root view of the Volume Dialog. */
@OptIn(ExperimentalCoroutinesApi::class)
@VolumeDialogScope
class VolumeDialogViewBinder
@Inject
constructor(
- @Main resources: Resources,
private val viewModel: VolumeDialogViewModel,
private val jankListenerFactory: JankListenerFactory,
private val tracer: VolumeTracer,
- private val volumeDialogRingerViewBinder: VolumeDialogRingerViewBinder,
- private val slidersViewBinder: VolumeDialogSlidersViewBinder,
- private val settingsButtonViewBinder: VolumeDialogSettingsButtonViewBinder,
+ private val viewBinders: List<@JvmSuppressWildcards ViewBinder>,
) {
- private val dialogShowAnimationDurationMs =
- resources.getInteger(R.integer.config_dialogShowAnimationDurationMs).toLong()
- private val dialogHideAnimationDurationMs =
- resources.getInteger(R.integer.config_dialogHideAnimationDurationMs).toLong()
-
fun CoroutineScope.bind(dialog: Dialog) {
val insets: MutableStateFlow<WindowInsets> =
MutableStateFlow(WindowInsets.Builder().build())
@@ -105,9 +104,9 @@ constructor(
.awaitCancellationThenDispose()
}
- with(volumeDialogRingerViewBinder) { bind(root) }
- with(slidersViewBinder) { bind(root) }
- with(settingsButtonViewBinder) { bind(root) }
+ for (viewBinder in viewBinders) {
+ with(viewBinder) { bind(root) }
+ }
}
private fun CoroutineScope.animateVisibility(
@@ -115,22 +114,35 @@ constructor(
dialog: Dialog,
visibilityModel: Flow<VolumeDialogVisibilityModel>,
) {
+ view.applyAnimationProgress(FRACTION_HIDE)
+ val animationValueHolder = FloatValueHolder(FRACTION_HIDE)
+ val animation: SpringAnimation =
+ SpringAnimation(animationValueHolder)
+ .setSpring(
+ SpringForce()
+ .setStiffness(SPRING_STIFFNESS)
+ .setDampingRatio(SPRING_DAMPING_RATIO)
+ )
+ .setMinimumVisibleChange(ANIMATION_MINIMUM_VISIBLE_CHANGE)
+ .addUpdateListener { _, value, _ -> view.applyAnimationProgress(value) }
+ var junkListener: DynamicAnimation.OnAnimationUpdateListener? = null
+
visibilityModel
.mapLatest {
when (it) {
is VolumeDialogVisibilityModel.Visible -> {
tracer.traceVisibilityEnd(it)
- view.animateShow(
- duration = dialogShowAnimationDurationMs,
- translationX = calculateTranslationX(view),
- )
+ junkListener?.let(animation::removeUpdateListener)
+ junkListener =
+ jankListenerFactory.show(view).also(animation::addUpdateListener)
+ animation.suspendAnimate(FRACTION_SHOW)
}
is VolumeDialogVisibilityModel.Dismissed -> {
tracer.traceVisibilityEnd(it)
- view.animateHide(
- duration = dialogHideAnimationDurationMs,
- translationX = calculateTranslationX(view),
- )
+ junkListener?.let(animation::removeUpdateListener)
+ junkListener =
+ jankListenerFactory.dismiss(view).also(animation::addUpdateListener)
+ animation.suspendAnimate(FRACTION_HIDE)
dialog.dismiss()
}
is VolumeDialogVisibilityModel.Invisible -> {
@@ -141,37 +153,21 @@ constructor(
.launchIn(this)
}
- private fun calculateTranslationX(view: View): Float? {
- return if (view.display.rotation == RotationPolicy.NATURAL_ROTATION) {
- if (view.isLayoutRtl) {
- -1
+ /**
+ * @param fraction in range [0, 1]. 0 corresponds to the dialog being hidden and 1 - visible.
+ */
+ private fun View.applyAnimationProgress(fraction: Float) {
+ alpha = ceil(fraction)
+ if (display.rotation == RotationPolicy.NATURAL_ROTATION) {
+ if (isLayoutRtl) {
+ -1
+ } else {
+ 1
+ } * width / 2f
} else {
- 1
- } * view.width / 2f
- } else {
- null
- }
- }
-
- private suspend fun View.animateShow(duration: Long, translationX: Float?) {
- translationX?.let { setTranslationX(translationX) }
- alpha = 0f
- animate()
- .alpha(1f)
- .translationX(0f)
- .setDuration(duration)
- .setInterpolator(SystemUIInterpolators.LogDecelerateInterpolator())
- .suspendAnimate(jankListenerFactory.show(this, duration))
- }
-
- private suspend fun View.animateHide(duration: Long, translationX: Float?) {
- val animator =
- animate()
- .alpha(0f)
- .setDuration(duration)
- .setInterpolator(SystemUIInterpolators.LogAccelerateInterpolator())
- translationX?.let { animator.translationX(it) }
- animator.suspendAnimate(jankListenerFactory.dismiss(this, duration))
+ null
+ }
+ ?.let { maxTranslationX -> translationX = lerp(maxTranslationX, 0f, fraction) }
}
private suspend fun ViewTreeObserver.listenToComputeInternalInsets() =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/JankListenerFactory.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/JankListenerFactory.kt
index 9fcd77716fb6..803911a9cf77 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/JankListenerFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/JankListenerFactory.kt
@@ -17,8 +17,8 @@
package com.android.systemui.volume.dialog.ui.utils
import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
import android.view.View
+import androidx.dynamicanimation.animation.DynamicAnimation
import com.android.internal.jank.Cuj
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
@@ -30,35 +30,36 @@ class JankListenerFactory
@Inject
constructor(private val interactionJankMonitor: InteractionJankMonitor) {
- fun show(view: View, timeout: Long) = getJunkListener(view, "show", timeout)
-
- fun update(view: View, timeout: Long) = getJunkListener(view, "update", timeout)
+ fun show(view: View): DynamicAnimation.OnAnimationUpdateListener {
+ return createJunkListener(view, "show")
+ }
- fun dismiss(view: View, timeout: Long) = getJunkListener(view, "dismiss", timeout)
+ fun dismiss(view: View): DynamicAnimation.OnAnimationUpdateListener {
+ return createJunkListener(view, "dismiss")
+ }
- private fun getJunkListener(
+ private fun createJunkListener(
view: View,
type: String,
- timeout: Long,
- ): Animator.AnimatorListener {
- return object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator) {
+ ): DynamicAnimation.OnAnimationUpdateListener {
+ var trackedStart = false
+ return DynamicAnimation.OnAnimationUpdateListener { animation, _, _ ->
+ if (!trackedStart) {
+ trackedStart = true
interactionJankMonitor.begin(
InteractionJankMonitor.Configuration.Builder.withView(
Cuj.CUJ_VOLUME_CONTROL,
view,
)
.setTag(type)
- .setTimeout(timeout)
)
- }
-
- override fun onAnimationEnd(animation: Animator) {
- interactionJankMonitor.end(Cuj.CUJ_VOLUME_CONTROL)
- }
-
- override fun onAnimationCancel(animation: Animator) {
- interactionJankMonitor.cancel(Cuj.CUJ_VOLUME_CONTROL)
+ animation.addEndListener { _, canceled, _, _ ->
+ if (canceled) {
+ interactionJankMonitor.cancel(Cuj.CUJ_VOLUME_CONTROL)
+ } else {
+ interactionJankMonitor.end(Cuj.CUJ_VOLUME_CONTROL)
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt
index 52a19e0903e2..31e596f0278d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt
@@ -96,21 +96,23 @@ suspend fun <T> ValueAnimator.suspendAnimate(onValueChanged: (T) -> Unit) {
* Starts spring animation and suspends until it's finished. Cancels the animation if the running
* coroutine is cancelled.
*/
-suspend fun SpringAnimation.suspendAnimate(onAnimationUpdate: (Float) -> Unit) =
- suspendCancellableCoroutine { continuation ->
- val updateListener =
- DynamicAnimation.OnAnimationUpdateListener { _, value, _ -> onAnimationUpdate(value) }
- val endListener =
- DynamicAnimation.OnAnimationEndListener { _, _, _, _ -> continuation.resumeIfCan(Unit) }
- addUpdateListener(updateListener)
- addEndListener(endListener)
- animateToFinalPosition(1F)
- continuation.invokeOnCancellation {
- removeUpdateListener(updateListener)
- removeEndListener(endListener)
- cancel()
- }
+suspend fun SpringAnimation.suspendAnimate(
+ finalPosition: Float = 1f,
+ onAnimationUpdate: (Float) -> Unit = {},
+) = suspendCancellableCoroutine { continuation ->
+ val updateListener =
+ DynamicAnimation.OnAnimationUpdateListener { _, value, _ -> onAnimationUpdate(value) }
+ val endListener =
+ DynamicAnimation.OnAnimationEndListener { _, _, _, _ -> continuation.resumeIfCan(Unit) }
+ addUpdateListener(updateListener)
+ addEndListener(endListener)
+ animateToFinalPosition(finalPosition)
+ continuation.invokeOnCancellation {
+ removeUpdateListener(updateListener)
+ removeEndListener(endListener)
+ cancel()
}
+}
/**
* Starts the animation and suspends until it's finished. Cancels the animation if the running
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt
index e2d2f3f68c6b..3efb2b464a1d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModel.kt
@@ -16,7 +16,6 @@
package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
-import android.content.Context
import com.android.internal.logging.UiEventLogger
import com.android.systemui.Flags
import com.android.systemui.common.shared.model.Icon
@@ -24,6 +23,7 @@ import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.res.R
import com.android.systemui.volume.domain.interactor.AudioSharingInteractor
+import com.android.systemui.volume.panel.shared.VolumePanelLogger
import com.android.systemui.volume.panel.ui.VolumePanelUiEvent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -34,6 +34,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -43,21 +44,25 @@ class AudioSharingStreamSliderViewModel
@AssistedInject
constructor(
@Assisted private val coroutineScope: CoroutineScope,
- private val context: Context,
private val audioSharingInteractor: AudioSharingInteractor,
private val uiEventLogger: UiEventLogger,
private val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
+ private val volumePanelLogger: VolumePanelLogger,
) : SliderViewModel {
private val volumeChanges = MutableStateFlow<Int?>(null)
override val slider: StateFlow<SliderState> =
- combine(audioSharingInteractor.volume, audioSharingInteractor.secondaryDevice) {
- volume,
- device ->
+ combine(
+ audioSharingInteractor.volume.distinctUntilChanged().onEach {
+ it?.let(volumePanelLogger::onAudioSharingVolumeUpdateReceived)
+ },
+ audioSharingInteractor.secondaryDevice,
+ ) { volume, device ->
val deviceName = device?.name ?: return@combine SliderState.Empty
if (volume == null) {
SliderState.Empty
} else {
+
State(
value = volume.toFloat(),
valueRange =
@@ -74,13 +79,15 @@ constructor(
init {
volumeChanges
.filterNotNull()
- .onEach { audioSharingInteractor.setStreamVolume(it) }
+ .onEach {
+ volumePanelLogger.onSetAudioSharingVolumeRequested(it)
+ audioSharingInteractor.setStreamVolume(it)
+ }
.launchIn(coroutineScope)
}
override fun onValueChanged(state: SliderState, newValue: Float) {
- val audioViewModel = state as? State
- audioViewModel ?: return
+ if (state !is State) return
volumeChanges.tryEmit(newValue.roundToInt())
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
index 533276413ade..d74a433ad86c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
@@ -26,6 +26,7 @@ import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
+import com.android.systemui.volume.panel.shared.VolumePanelLogger
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -44,17 +45,23 @@ constructor(
private val context: Context,
private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,
private val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
+ private val volumePanelLogger: VolumePanelLogger,
) : SliderViewModel {
override val slider: StateFlow<SliderState> =
mediaDeviceSessionInteractor
.playbackInfo(session)
- .mapNotNull { it?.getCurrentState() }
+ .mapNotNull {
+ volumePanelLogger.onVolumeUpdateReceived(session.sessionToken, it.currentVolume)
+ it.getCurrentState()
+ }
.stateIn(coroutineScope, SharingStarted.Eagerly, SliderState.Empty)
override fun onValueChanged(state: SliderState, newValue: Float) {
coroutineScope.launch {
- mediaDeviceSessionInteractor.setSessionVolume(session, newValue.roundToInt())
+ val volume = newValue.roundToInt()
+ volumePanelLogger.onSetVolumeRequested(session.sessionToken, volume)
+ mediaDeviceSessionInteractor.setSessionVolume(session, volume)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/shared/VolumePanelLogger.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/shared/VolumePanelLogger.kt
index 276326cbf430..930199a03a56 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/shared/VolumePanelLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/shared/VolumePanelLogger.kt
@@ -16,6 +16,8 @@
package com.android.systemui.volume.panel.shared
+import android.media.session.MediaSession
+import android.media.session.MediaSession.Token
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
@@ -42,7 +44,7 @@ class VolumePanelLogger @Inject constructor(@VolumeLog private val logBuffer: Lo
str1 = key
bool1 = isAvailable
},
- { "$str1 isAvailable=$bool1" }
+ { "$str1 isAvailable=$bool1" },
)
}
@@ -51,7 +53,7 @@ class VolumePanelLogger @Inject constructor(@VolumeLog private val logBuffer: Lo
TAG,
LogLevel.DEBUG,
{ bool1 = globalState.isVisible },
- { "Global state changed: isVisible=$bool1" }
+ { "Global state changed: isVisible=$bool1" },
)
}
@@ -63,7 +65,7 @@ class VolumePanelLogger @Inject constructor(@VolumeLog private val logBuffer: Lo
str1 = audioStream.toString()
int1 = volume
},
- { "Set volume: stream=$str1 volume=$int1" }
+ { "Set volume: stream=$str1 volume=$int1" },
)
}
@@ -75,7 +77,49 @@ class VolumePanelLogger @Inject constructor(@VolumeLog private val logBuffer: Lo
str1 = audioStream.toString()
int1 = volume
},
- { "Volume update received: stream=$str1 volume=$int1" }
+ { "Volume update received: stream=$str1 volume=$int1" },
+ )
+ }
+
+ fun onSetVolumeRequested(sessionToken: MediaSession.Token, volume: Int) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = sessionToken.toString()
+ int1 = volume
+ },
+ { "Set volume: token=$str1 volume=$int1" },
+ )
+ }
+
+ fun onVolumeUpdateReceived(sessionToken: Token, volume: Int) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = sessionToken.toString()
+ int1 = volume
+ },
+ { "Volume update received: token=$str1 volume=$int1" },
+ )
+ }
+
+ fun onSetAudioSharingVolumeRequested(volume: Int) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { int1 = volume },
+ { "Set volume: audio-sharing volume=$int1" },
+ )
+ }
+
+ fun onAudioSharingVolumeUpdateReceived(volume: Int) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { int1 = volume },
+ { "Volume update received: audio-sharing volume=$int1" },
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt
index ec74f4f47bc9..300a7e070b6c 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt
@@ -17,6 +17,8 @@
package com.android.systemui.wallpapers.data.repository
import android.app.WallpaperInfo
+import android.graphics.PointF
+import android.graphics.RectF
import android.view.View
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
@@ -37,4 +39,8 @@ class NoopWallpaperRepository @Inject constructor() : WallpaperRepository {
override val wallpaperSupportsAmbientMode = flowOf(false)
override var rootView: View? = null
override val shouldSendFocalArea: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
+
+ override fun sendLockScreenLayoutChangeCommand(wallpaperFocalAreaBounds: RectF) {}
+
+ override fun sendTapCommand(tapPosition: PointF) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt
index 2c3491b06a90..974468c16578 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt
@@ -33,7 +33,8 @@ interface WallpaperFocalAreaRepository {
val wallpaperFocalAreaBounds: StateFlow<RectF>
- val wallpaperFocalAreaTapPosition: StateFlow<PointF>
+ /** It will be true when wallpaper requires focal area info. */
+ val hasFocalArea: StateFlow<Boolean>
/** top of notifications without bcsmartspace in small clock settings */
val notificationDefaultTop: StateFlow<Float>
@@ -51,7 +52,9 @@ interface WallpaperFocalAreaRepository {
}
@SysUISingleton
-class WallpaperFocalAreaRepositoryImpl @Inject constructor() : WallpaperFocalAreaRepository {
+class WallpaperFocalAreaRepositoryImpl
+@Inject
+constructor(val wallpaperRepository: WallpaperRepository) : WallpaperFocalAreaRepository {
private val _shortcutAbsoluteTop = MutableStateFlow(0F)
override val shortcutAbsoluteTop = _shortcutAbsoluteTop.asStateFlow()
@@ -63,13 +66,11 @@ class WallpaperFocalAreaRepositoryImpl @Inject constructor() : WallpaperFocalAre
override val wallpaperFocalAreaBounds: StateFlow<RectF> =
_wallpaperFocalAreaBounds.asStateFlow()
- private val _wallpaperFocalAreaTapPosition = MutableStateFlow(PointF(0F, 0F))
- override val wallpaperFocalAreaTapPosition: StateFlow<PointF> =
- _wallpaperFocalAreaTapPosition.asStateFlow()
-
private val _notificationDefaultTop = MutableStateFlow(0F)
override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow()
+ override val hasFocalArea = wallpaperRepository.shouldSendFocalArea
+
override fun setShortcutAbsoluteTop(top: Float) {
_shortcutAbsoluteTop.value = top
}
@@ -84,9 +85,10 @@ class WallpaperFocalAreaRepositoryImpl @Inject constructor() : WallpaperFocalAre
override fun setWallpaperFocalAreaBounds(bounds: RectF) {
_wallpaperFocalAreaBounds.value = bounds
+ wallpaperRepository.sendLockScreenLayoutChangeCommand(bounds)
}
- override fun setTapPosition(point: PointF) {
- _wallpaperFocalAreaTapPosition.value = point
+ override fun setTapPosition(tapPosition: PointF) {
+ wallpaperRepository.sendTapCommand(tapPosition)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
index a34a2ddb7713..b07342c4c76d 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
@@ -21,31 +21,29 @@ import android.app.WallpaperManager
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.graphics.PointF
+import android.graphics.RectF
import android.os.Bundle
import android.os.UserHandle
+import android.provider.Settings
+import android.util.Log
import android.view.View
-import androidx.annotation.VisibleForTesting
-import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.Edge
-import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.res.R as SysUIR
-import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shared.Flags.ambientAod
import com.android.systemui.shared.Flags.extendedWallpaperEffects
import com.android.systemui.user.data.model.SelectedUserModel
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import com.android.systemui.utils.coroutines.flow.mapLatestConflated
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -54,7 +52,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
@@ -73,6 +71,10 @@ interface WallpaperRepository {
/** some wallpapers require bounds to be sent from keyguard */
val shouldSendFocalArea: StateFlow<Boolean>
+
+ fun sendLockScreenLayoutChangeCommand(wallpaperFocalAreaBounds: RectF)
+
+ fun sendTapCommand(tapPosition: PointF)
}
@SysUISingleton
@@ -83,10 +85,9 @@ constructor(
@Background private val bgDispatcher: CoroutineDispatcher,
broadcastDispatcher: BroadcastDispatcher,
userRepository: UserRepository,
- wallpaperFocalAreaRepository: WallpaperFocalAreaRepository,
private val wallpaperManager: WallpaperManager,
private val context: Context,
- keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val secureSettings: SecureSettings,
) : WallpaperRepository {
private val wallpaperChanged: Flow<Unit> =
broadcastDispatcher
@@ -105,9 +106,6 @@ constructor(
// Only update the wallpaper status once the user selection has finished.
.filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE }
- @VisibleForTesting var sendLockscreenLayoutJob: Job? = null
- @VisibleForTesting var sendTapInShapeEffectsJob: Job? = null
-
override val wallpaperInfo: StateFlow<WallpaperInfo?> =
if (!wallpaperManager.isWallpaperSupported) {
MutableStateFlow(null).asStateFlow()
@@ -125,81 +123,59 @@ constructor(
}
override val wallpaperSupportsAmbientMode: Flow<Boolean> =
- flowOf(context.resources.getBoolean(R.bool.config_dozeSupportsAodWallpaper) && ambientAod())
+ secureSettings
+ .observerFlow(UserHandle.USER_ALL, Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED)
+ .onStart { emit(Unit) }
+ .map {
+ val userEnabled =
+ secureSettings.getInt(Settings.Secure.DOZE_ALWAYS_ON_WALLPAPER_ENABLED, 1) == 1
+ userEnabled &&
+ context.resources.getBoolean(R.bool.config_dozeSupportsAodWallpaper) &&
+ ambientAod()
+ }
+ .flowOn(bgDispatcher)
override var rootView: View? = null
+ override fun sendLockScreenLayoutChangeCommand(wallpaperFocalAreaBounds: RectF) {
+ if (DEBUG) {
+ Log.d(TAG, "sendLockScreenLayoutChangeCommand $wallpaperFocalAreaBounds")
+ }
+ wallpaperManager.sendWallpaperCommand(
+ /* windowToken = */ rootView?.windowToken,
+ /* action = */ WallpaperManager.COMMAND_LOCKSCREEN_LAYOUT_CHANGED,
+ /* x = */ 0,
+ /* y = */ 0,
+ /* z = */ 0,
+ /* extras = */ Bundle().apply {
+ putFloat("wallpaperFocalAreaLeft", wallpaperFocalAreaBounds.left)
+ putFloat("wallpaperFocalAreaRight", wallpaperFocalAreaBounds.right)
+ putFloat("wallpaperFocalAreaTop", wallpaperFocalAreaBounds.top)
+ putFloat("wallpaperFocalAreaBottom", wallpaperFocalAreaBounds.bottom)
+ },
+ )
+ }
+
+ override fun sendTapCommand(tapPosition: PointF) {
+ if (DEBUG) {
+ Log.d(TAG, "sendTapCommand $tapPosition")
+ }
+
+ wallpaperManager.sendWallpaperCommand(
+ /* windowToken = */ rootView?.windowToken,
+ /* action = */ WallpaperManager.COMMAND_LOCKSCREEN_TAP,
+ /* x = */ tapPosition.x.toInt(),
+ /* y = */ tapPosition.y.toInt(),
+ /* z = */ 0,
+ /* extras = */ Bundle(),
+ )
+ }
+
override val shouldSendFocalArea =
wallpaperInfo
.map {
val focalAreaTarget = context.resources.getString(SysUIR.string.focal_area_target)
val shouldSendNotificationLayout = it?.component?.className == focalAreaTarget
- if (shouldSendNotificationLayout) {
- sendLockscreenLayoutJob =
- scope.launch {
- combine(
- wallpaperFocalAreaRepository.wallpaperFocalAreaBounds,
- keyguardTransitionInteractor
- .transition(
- edge = Edge.create(to = Scenes.Lockscreen),
- edgeWithoutSceneContainer =
- Edge.create(to = KeyguardState.LOCKSCREEN),
- )
- .filter { transitionStep ->
- transitionStep.transitionState ==
- TransitionState.STARTED
- },
- ::Pair,
- )
- .map { (bounds, _) -> bounds }
- .collect { wallpaperFocalAreaBounds ->
- wallpaperManager.sendWallpaperCommand(
- /* windowToken = */ rootView?.windowToken,
- /* action = */ WallpaperManager
- .COMMAND_LOCKSCREEN_LAYOUT_CHANGED,
- /* x = */ 0,
- /* y = */ 0,
- /* z = */ 0,
- /* extras = */ Bundle().apply {
- putFloat(
- "wallpaperFocalAreaLeft",
- wallpaperFocalAreaBounds.left,
- )
- putFloat(
- "wallpaperFocalAreaRight",
- wallpaperFocalAreaBounds.right,
- )
- putFloat(
- "wallpaperFocalAreaTop",
- wallpaperFocalAreaBounds.top,
- )
- putFloat(
- "wallpaperFocalAreaBottom",
- wallpaperFocalAreaBounds.bottom,
- )
- },
- )
- }
- }
-
- sendTapInShapeEffectsJob =
- scope.launch {
- wallpaperFocalAreaRepository.wallpaperFocalAreaTapPosition.collect {
- wallpaperFocalAreaTapPosition ->
- wallpaperManager.sendWallpaperCommand(
- /* windowToken = */ rootView?.windowToken,
- /* action = */ WallpaperManager.COMMAND_LOCKSCREEN_TAP,
- /* x = */ wallpaperFocalAreaTapPosition.x.toInt(),
- /* y = */ wallpaperFocalAreaTapPosition.y.toInt(),
- /* z = */ 0,
- /* extras = */ null,
- )
- }
- }
- } else {
- sendLockscreenLayoutJob?.cancel()
- sendTapInShapeEffectsJob?.cancel()
- }
shouldSendNotificationLayout
}
.stateIn(
@@ -213,4 +189,9 @@ constructor(
wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id)
}
}
+
+ companion object {
+ private val TAG = WallpaperRepositoryImpl::class.simpleName
+ private val DEBUG = true
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
index 187d6c7801c0..09c6cdf0ce22 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
@@ -20,60 +20,38 @@ import android.content.Context
import android.content.res.Resources
import android.graphics.PointF
import android.graphics.RectF
+import android.util.Log
import android.util.TypedValue
-import androidx.annotation.VisibleForTesting
import com.android.app.animation.MathUtils
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.res.R
import com.android.systemui.shade.data.repository.ShadeRepository
-import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.wallpapers.data.repository.WallpaperFocalAreaRepository
-import com.android.systemui.wallpapers.data.repository.WallpaperRepository
import javax.inject.Inject
import kotlin.math.min
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
@SysUISingleton
class WallpaperFocalAreaInteractor
@Inject
constructor(
- @Application private val applicationScope: CoroutineScope,
private val context: Context,
private val wallpaperFocalAreaRepository: WallpaperFocalAreaRepository,
shadeRepository: ShadeRepository,
- activeNotificationsInteractor: ActiveNotificationsInteractor,
- val wallpaperRepository: WallpaperRepository,
) {
- // When there's notifications in splitshade, the focal area should be left aligned
- @VisibleForTesting
- val notificationInShadeWideLayout: Flow<Boolean> =
- combine(
- shadeRepository.isShadeLayoutWide,
- activeNotificationsInteractor.areAnyNotificationsPresent,
- ) { isShadeLayoutWide, areAnyNotificationsPresent: Boolean ->
- when {
- !isShadeLayoutWide -> false
- !areAnyNotificationsPresent -> false
- else -> true
- }
- }
-
- val hasFocalArea = wallpaperRepository.shouldSendFocalArea
+ val hasFocalArea = wallpaperFocalAreaRepository.hasFocalArea
val wallpaperFocalAreaBounds: Flow<RectF> =
combine(
shadeRepository.isShadeLayoutWide,
- notificationInShadeWideLayout,
wallpaperFocalAreaRepository.notificationStackAbsoluteBottom,
wallpaperFocalAreaRepository.shortcutAbsoluteTop,
wallpaperFocalAreaRepository.notificationDefaultTop,
) {
isShadeLayoutWide,
- notificationInShadeWideLayout,
notificationStackAbsoluteBottom,
shortcutAbsoluteTop,
notificationDefaultTop ->
@@ -97,28 +75,21 @@ constructor(
screenBounds.centerY() + screenBounds.height() / 2F / wallpaperZoomedInScale,
)
+ val focalAreaMaxWidthDp = getFocalAreaMaxWidthDp(context)
val maxFocalAreaWidth =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
- FOCAL_AREA_MAX_WIDTH_DP.toFloat(),
+ focalAreaMaxWidthDp.toFloat(),
context.resources.displayMetrics,
)
val (left, right) =
- // tablet landscape
- if (context.resources.getBoolean(R.bool.center_align_focal_area_shape)) {
+ // Tablet & unfold foldable landscape
+ if (isShadeLayoutWide) {
Pair(
scaledBounds.centerX() - maxFocalAreaWidth / 2F,
scaledBounds.centerX() + maxFocalAreaWidth / 2F,
)
- // unfold foldable landscape
- } else if (isShadeLayoutWide) {
- if (notificationInShadeWideLayout) {
- Pair(scaledBounds.left, scaledBounds.centerX())
- } else {
- Pair(scaledBounds.centerX(), scaledBounds.right)
- }
- // handheld / portrait
} else {
val focalAreaWidth = min(scaledBounds.width(), maxFocalAreaWidth)
Pair(
@@ -147,8 +118,10 @@ constructor(
wallpaperZoomedInScale
}
val bottom = scaledBounds.bottom - scaledBottomMargin
- RectF(left, top, right, bottom)
+ RectF(left, top, right, bottom).also { Log.d(TAG, "Focal area changes to $it") }
}
+ // Make sure a valid rec
+ .filter { it.width() >= 0 && it.height() >= 0 }
.distinctUntilChanged()
fun setFocalAreaBounds(bounds: RectF) {
@@ -187,8 +160,17 @@ constructor(
return if (scale == 0f) 1f else scale
}
- // A max width for focal area shape effects bounds, to avoid
- // it becoming too large in large screen portrait mode
- const val FOCAL_AREA_MAX_WIDTH_DP = 500
+ // A max width for focal area shape effects bounds, to avoid it becoming too large,
+ // especially in portrait mode
+ const val FOCAL_AREA_MAX_WIDTH_DP_TABLET = 500
+ const val FOCAL_AREA_MAX_WIDTH_DP_FOLDABLE = 400
+
+ fun getFocalAreaMaxWidthDp(context: Context): Int {
+ return if (context.resources.getBoolean(R.bool.center_align_focal_area_shape))
+ FOCAL_AREA_MAX_WIDTH_DP_TABLET
+ else FOCAL_AREA_MAX_WIDTH_DP_FOLDABLE
+ }
+
+ private val TAG = WallpaperFocalAreaInteractor::class.simpleName
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
index 70a97d473c49..4cd49d03ad36 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
@@ -17,15 +17,41 @@
package com.android.systemui.wallpapers.ui.viewmodel
import android.graphics.RectF
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.Edge
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor
import javax.inject.Inject
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
class WallpaperFocalAreaViewModel
@Inject
-constructor(private val wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor) {
+constructor(
+ private val wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor,
+ val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+) {
val hasFocalArea = wallpaperFocalAreaInteractor.hasFocalArea
- val wallpaperFocalAreaBounds = wallpaperFocalAreaInteractor.wallpaperFocalAreaBounds
+ val wallpaperFocalAreaBounds =
+ combine(
+ wallpaperFocalAreaInteractor.wallpaperFocalAreaBounds,
+ keyguardTransitionInteractor
+ .transition(
+ edge = Edge.create(to = Scenes.Lockscreen),
+ edgeWithoutSceneContainer = Edge.create(to = KeyguardState.LOCKSCREEN),
+ )
+ .filter { transitionStep ->
+ // Should not filter by TransitionState.STARTED, it may race with
+ // wakingup command, causing layout change command not be received.
+ transitionStep.transitionState == TransitionState.FINISHED
+ },
+ ::Pair,
+ )
+ .map { (bounds, _) -> bounds }
fun setFocalAreaBounds(bounds: RectF) {
wallpaperFocalAreaInteractor.setFocalAreaBounds(bounds)
diff --git a/packages/SystemUI/src/com/android/systemui/window/data/repository/NoopWindowRootViewBlurRepository.kt b/packages/SystemUI/src/com/android/systemui/window/data/repository/NoopWindowRootViewBlurRepository.kt
index 80aa11a71569..f1dd374d3e1d 100644
--- a/packages/SystemUI/src/com/android/systemui/window/data/repository/NoopWindowRootViewBlurRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/window/data/repository/NoopWindowRootViewBlurRepository.kt
@@ -25,4 +25,5 @@ class NoopWindowRootViewBlurRepository @Inject constructor() : WindowRootViewBlu
override val blurRadius: MutableStateFlow<Int> = MutableStateFlow(0)
override val isBlurOpaque: MutableStateFlow<Boolean> = MutableStateFlow(true)
override val isBlurSupported: StateFlow<Boolean> = MutableStateFlow(false)
-} \ No newline at end of file
+ override var blurAppliedListener: BlurAppliedListener? = null
+}
diff --git a/packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt b/packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt
index 41ceda033bdf..f98efe1e3c33 100644
--- a/packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt
@@ -26,6 +26,7 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import com.android.systemui.window.data.repository.WindowRootViewBlurRepository.Companion.isDisableBlurSysPropSet
import java.util.concurrent.Executor
+import java.util.function.Consumer
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
@@ -34,6 +35,8 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
+typealias BlurAppliedListener = Consumer<Int>
+
/** Repository that maintains state for the window blur effect. */
interface WindowRootViewBlurRepository {
val blurRadius: MutableStateFlow<Int>
@@ -42,6 +45,8 @@ interface WindowRootViewBlurRepository {
/** Is blur supported based on settings toggle and battery power saver mode. */
val isBlurSupported: StateFlow<Boolean>
+ var blurAppliedListener: BlurAppliedListener?
+
companion object {
/**
* Whether the `persist.sysui.disableBlur` is set, this is used to disable blur for tests.
@@ -82,6 +87,8 @@ constructor(
} // stateIn because this is backed by a binder call.
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ override var blurAppliedListener: BlurAppliedListener? = null
+
private fun isBlurAllowed(): Boolean {
return ActivityManager.isHighEndGfx() && !isDisableBlurSysPropSet()
}
diff --git a/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt b/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt
index 7a88a2ef966b..5197242e8079 100644
--- a/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt
@@ -16,7 +16,6 @@
package com.android.systemui.window.domain.interactor
-import android.annotation.SuppressLint
import android.util.Log
import com.android.systemui.Flags
import com.android.systemui.communal.domain.interactor.CommunalInteractor
@@ -25,11 +24,11 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
+import com.android.systemui.window.data.repository.BlurAppliedListener
import com.android.systemui.window.data.repository.WindowRootViewBlurRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -54,8 +53,6 @@ constructor(
private val communalInteractor: CommunalInteractor,
private val repository: WindowRootViewBlurRepository,
) {
- @SuppressLint("SharedFlowCreation") private val _onBlurAppliedEvent = MutableSharedFlow<Int>()
-
private var isBouncerTransitionInProgress: StateFlow<Boolean> =
if (Flags.bouncerUiRevamp()) {
keyguardTransitionInteractor
@@ -71,8 +68,16 @@ constructor(
* Invoked by the view after blur of [appliedBlurRadius] was successfully applied on the window
* root view.
*/
- suspend fun onBlurApplied(appliedBlurRadius: Int) {
- _onBlurAppliedEvent.emit(appliedBlurRadius)
+ fun onBlurApplied(appliedBlurRadius: Int) {
+ repository.blurAppliedListener?.accept(appliedBlurRadius)
+ }
+
+ /**
+ * Register a listener that gets invoked whenever blur is applied, clears the listener if the
+ * passed in value is null
+ */
+ fun registerBlurAppliedListener(listener: BlurAppliedListener?) {
+ repository.blurAppliedListener = listener
}
/**
@@ -84,11 +89,6 @@ constructor(
/** Radius of blur to be applied on the window root view. */
val blurRadius: StateFlow<Int> = repository.blurRadius.asStateFlow()
- /**
- * Emits the applied blur radius whenever blur is successfully applied to the window root view.
- */
- val onBlurAppliedEvent: Flow<Int> = _onBlurAppliedEvent
-
/** Whether the blur applied is opaque or transparent. */
val isBlurOpaque: Flow<Boolean> =
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt
index 153df7f29737..06532bc0cc2a 100644
--- a/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt
@@ -84,9 +84,16 @@ object WindowRootViewBinder {
combine(viewModel.blurRadius, viewModel.isBlurOpaque, ::Pair)
.filter { it.first >= 0 }
.collect { (blurRadius, isOpaque) ->
- // Expectation is that we schedule only one blur radius value
- // per frame
+ val newBlurRadius = blurRadius.toInt()
+ // Expectation is that we schedule only one frame callback per frame
if (wasUpdateScheduledForThisFrame) {
+ // Update this value so that the frame callback picks up this
+ // value when it runs
+ if (lastScheduledBlurRadius != newBlurRadius) {
+ Log.w(TAG, "Multiple blur values emitted in the same frame")
+ }
+ lastScheduledBlurRadius = newBlurRadius
+ lastScheduleBlurOpaqueness = isOpaque
return@collect
}
TrackTracer.instantForGroup(
@@ -94,7 +101,7 @@ object WindowRootViewBinder {
"preparedBlurRadius",
blurRadius,
)
- lastScheduledBlurRadius = blurRadius.toInt()
+ lastScheduledBlurRadius = newBlurRadius
lastScheduleBlurOpaqueness = isOpaque
wasUpdateScheduledForThisFrame = true
blurUtils.prepareBlur(
diff --git a/packages/SystemUI/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModel.kt
index b18c39dcf5e0..e60e85335f7a 100644
--- a/packages/SystemUI/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModel.kt
@@ -18,35 +18,30 @@ package com.android.systemui.window.ui.viewmodel
import android.os.Build
import android.util.Log
-import com.android.app.tracing.coroutines.launchTraced
import com.android.systemui.Flags
import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition
import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition
-import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-import kotlinx.coroutines.awaitCancellation
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
-typealias BlurAppliedUiEvent = Int
-
/** View model for window root view. */
+@OptIn(ExperimentalCoroutinesApi::class)
class WindowRootViewModel
@AssistedInject
constructor(
primaryBouncerTransitions: Set<@JvmSuppressWildcards PrimaryBouncerTransition>,
glanceableHubTransitions: Set<@JvmSuppressWildcards GlanceableHubTransition>,
private val blurInteractor: WindowRootViewBlurInteractor,
-) : ExclusiveActivatable() {
-
- private val blurEvents = Channel<BlurAppliedUiEvent>(Channel.BUFFERED)
+) {
private val bouncerBlurRadiusFlows =
if (Flags.bouncerUiRevamp())
@@ -58,7 +53,7 @@ constructor(
glanceableHubTransitions.map { it.windowBlurRadius.logIfPossible(it.javaClass.name) }
else emptyList()
- val blurRadius: Flow<Float> =
+ private val _blurRadius =
listOf(
*bouncerBlurRadiusFlows.toTypedArray(),
*glanceableHubBlurRadiusFlows.toTypedArray(),
@@ -66,25 +61,29 @@ constructor(
)
.merge()
- val isBlurOpaque =
- blurInteractor.isBlurOpaque.distinctUntilChanged().logIfPossible("isBlurOpaque")
+ val blurRadius: Flow<Float> =
+ blurInteractor.isBlurCurrentlySupported.flatMapLatest { blurSupported ->
+ if (blurSupported) {
+ _blurRadius
+ } else {
+ flowOf(0f)
+ }
+ }
- override suspend fun onActivated(): Nothing {
- coroutineScope {
- launchTraced("WindowRootViewModel#blurEvents") {
- for (event in blurEvents) {
- if (isLoggable) {
- Log.d(TAG, "blur applied for $event")
- }
- blurInteractor.onBlurApplied(event)
- }
+ val isBlurOpaque =
+ blurInteractor.isBlurCurrentlySupported.flatMapLatest { blurSupported ->
+ if (blurSupported) {
+ blurInteractor.isBlurOpaque.distinctUntilChanged().logIfPossible("isBlurOpaque")
+ } else {
+ flowOf(false)
}
}
- awaitCancellation()
- }
fun onBlurApplied(blurRadius: Int) {
- blurEvents.trySend(blurRadius)
+ if (isLoggable) {
+ Log.d(TAG, "blur applied for radius $blurRadius")
+ }
+ blurInteractor.onBlurApplied(blurRadius)
}
@AssistedFactory
@@ -101,9 +100,3 @@ constructor(
}
}
}
-
-/**
- * @property radius Radius of blur to be applied on the window root view.
- * @property isOpaque Whether the blur applied is opaque or transparent.
- */
-data class BlurState(val radius: Int, val isOpaque: Boolean)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/OnTeardownRuleTest.kt b/packages/SystemUI/tests/src/com/android/systemui/OnTeardownRuleTest.kt
index 8635bb0e8ab2..8635bb0e8ab2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/OnTeardownRuleTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/OnTeardownRuleTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java
index 6d75c4ca3a38..6d75c4ca3a38 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
index 4553f983b898..45b9f4ad2322 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
@@ -552,12 +552,23 @@ public class WindowMagnificationSettingsTest extends SysuiTestCase {
mockSeekBar,
OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER);
- // should trigger callback to update magnifier scale and persist the scale
+ // Should trigger callback to update magnifier scale and persist the scale.
verify(mWindowMagnificationSettingsCallback)
.onMagnifierScale(/* scale= */ eq(4f), /* updatePersistence= */ eq(true));
}
@Test
+ public void onSeekbarUserInteractionFinalized_notFromUser_persistedScaleNotUpdated() {
+ OnSeekBarWithIconButtonsChangeListener onChangeListener =
+ mZoomSeekbar.getOnSeekBarWithIconButtonsChangeListener();
+ onChangeListener.onProgressChanged(mZoomSeekbar.getSeekbar(), 30, false);
+
+ // Should not trigger callback to update magnifier scale and persist the scale.
+ verify(mWindowMagnificationSettingsCallback, never())
+ .onMagnifierScale(/* scale= */ anyFloat(), /* updatePersistence= */ eq(true));
+ }
+
+ @Test
public void seekbarProgress_scaleUpdatedAfterSettingPanelOpened_progressAlsoUpdated() {
setupMagnificationCapabilityAndMode(
/* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_ALL,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
index dcf38800bb01..14a81b3f8bfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
@@ -30,7 +30,6 @@ import kotlin.math.ceil
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.Mockito.eq
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
@@ -60,10 +59,11 @@ class TextAnimatorTest : SysuiTestCase() {
val textAnimator =
TextAnimator(layout, TypefaceVariantCacheImpl(typeface, 20)).apply {
this.textInterpolator = textInterpolator
+ this.createAnimator = { valueAnimator }
this.animator = valueAnimator
}
- textAnimator.setTextStyle(weight = 400, animate = true)
+ textAnimator.setTextStyle(TextAnimator.Style("'wght' 400"), TextAnimator.Animation())
// If animation is requested, the base state should be rebased and the target state should
// be updated.
@@ -90,10 +90,11 @@ class TextAnimatorTest : SysuiTestCase() {
val textAnimator =
TextAnimator(layout, TypefaceVariantCacheImpl(typeface, 20)).apply {
this.textInterpolator = textInterpolator
+ this.createAnimator = { valueAnimator }
this.animator = valueAnimator
}
- textAnimator.setTextStyle(weight = 400, animate = false)
+ textAnimator.setTextStyle(TextAnimator.Style("'wght' 400"))
// If animation is not requested, the progress should be 1 which is end of animation and the
// base state is rebased to target state by calling rebase.
@@ -118,23 +119,24 @@ class TextAnimatorTest : SysuiTestCase() {
val textAnimator =
TextAnimator(layout, TypefaceVariantCacheImpl(typeface, 20)).apply {
this.textInterpolator = textInterpolator
+ this.createAnimator = { valueAnimator }
this.animator = valueAnimator
}
textAnimator.setTextStyle(
- weight = 400,
- animate = true,
- onAnimationEnd = animationEndCallback,
+ TextAnimator.Style("'wght' 400"),
+ TextAnimator.Animation(animate = true, onAnimationEnd = animationEndCallback),
)
// Verify animationEnd callback has been added.
val captor = ArgumentCaptor.forClass(AnimatorListenerAdapter::class.java)
- verify(valueAnimator).addListener(captor.capture())
- captor.value.onAnimationEnd(valueAnimator)
+ verify(valueAnimator, times(2)).addListener(captor.capture())
+ for (callback in captor.allValues) {
+ callback.onAnimationEnd(valueAnimator)
+ }
// Verify animationEnd callback has been invoked and removed.
verify(animationEndCallback).run()
- verify(valueAnimator).removeListener(eq(captor.value))
}
@Test
@@ -148,18 +150,20 @@ class TextAnimatorTest : SysuiTestCase() {
val textAnimator =
TextAnimator(layout, TypefaceVariantCacheImpl(typeface, 20)).apply {
this.textInterpolator = textInterpolator
+ this.createAnimator = { valueAnimator }
this.animator = valueAnimator
}
- textAnimator.setTextStyle(weight = 400, animate = true)
+ val animation = TextAnimator.Animation(animate = true)
+ textAnimator.setTextStyle(TextAnimator.Style("'wght' 400"), animation)
val prevTypeface = paint.typeface
- textAnimator.setTextStyle(weight = 700, animate = true)
+ textAnimator.setTextStyle(TextAnimator.Style("'wght' 700"), animation)
assertThat(paint.typeface).isNotSameInstanceAs(prevTypeface)
- textAnimator.setTextStyle(weight = 400, animate = true)
+ textAnimator.setTextStyle(TextAnimator.Style("'wght' 400"), animation)
assertThat(paint.typeface).isSameInstanceAs(prevTypeface)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index b6c63479990e..b6c63479990e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegateTest.kt
index b4200b6850c8..b4200b6850c8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManagerTest.kt
index 6ed990d513cb..9c932695f295 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManagerTest.kt
@@ -87,7 +87,7 @@ class BluetoothDetailsContentManagerTest : SysuiTestCase() {
private val fakeSystemClock = FakeSystemClock()
private val uiProperties =
- BluetoothTileDialogViewModel.UiProperties.build(
+ BluetoothDetailsContentViewModel.UiProperties.build(
isBluetoothEnabled = ENABLED,
isAutoOnToggleFeatureAvailable = ENABLED,
)
@@ -314,7 +314,7 @@ class BluetoothDetailsContentManagerTest : SysuiTestCase() {
val cachedHeight = Int.MAX_VALUE
val contentManager =
BluetoothDetailsContentManager(
- BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+ BluetoothDetailsContentViewModel.UiProperties.build(ENABLED, ENABLED),
cachedHeight,
bluetoothTileDialogCallback,
/* isInDialog= */ true,
@@ -339,7 +339,7 @@ class BluetoothDetailsContentManagerTest : SysuiTestCase() {
testScope.runTest {
val contentManager =
BluetoothDetailsContentManager(
- BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+ BluetoothDetailsContentViewModel.UiProperties.build(ENABLED, ENABLED),
MATCH_PARENT,
bluetoothTileDialogCallback,
/* isInDialog= */ true,
@@ -364,7 +364,7 @@ class BluetoothDetailsContentManagerTest : SysuiTestCase() {
testScope.runTest {
val contentManager =
BluetoothDetailsContentManager(
- BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+ BluetoothDetailsContentViewModel.UiProperties.build(ENABLED, ENABLED),
MATCH_PARENT,
bluetoothTileDialogCallback,
/* isInDialog= */ true,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt
index 47a834be9b9c..bfc5361b6129 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt
@@ -67,14 +67,14 @@ import org.mockito.junit.MockitoRule
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@EnableFlags(Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE)
-class BluetoothTileDialogViewModelTest : SysuiTestCase() {
+class BluetoothDetailsContentViewModelTest : SysuiTestCase() {
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
private val kosmos = testKosmos()
private val fakeSystemClock = FakeSystemClock()
private val backgroundExecutor = FakeExecutor(fakeSystemClock)
- private lateinit var bluetoothTileDialogViewModel: BluetoothTileDialogViewModel
+ private lateinit var bluetoothDetailsContentViewModel: BluetoothDetailsContentViewModel
@Mock private lateinit var bluetoothDeviceMetadataInteractor: BluetoothDeviceMetadataInteractor
@@ -126,8 +126,8 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
testScope = kosmos.testScope
// TODO(b/364515243): use real object instead of mock
whenever(kosmos.deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow())
- bluetoothTileDialogViewModel =
- BluetoothTileDialogViewModel(
+ bluetoothDetailsContentViewModel =
+ BluetoothDetailsContentViewModel(
deviceItemInteractor,
deviceItemActionInteractor,
BluetoothStateInteractor(
@@ -194,7 +194,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
@Test
fun testShowDetailsContent_noAnimation() {
testScope.runTest {
- bluetoothTileDialogViewModel.showDetailsContent(null, null)
+ bluetoothDetailsContentViewModel.showDetailsContent(null, null)
runCurrent()
verify(mDialogTransitionAnimator, never()).show(any(), any(), any())
@@ -204,7 +204,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
@Test
fun testShowDetailsContent_animated() {
testScope.runTest {
- bluetoothTileDialogViewModel.showDetailsContent(expandable, null)
+ bluetoothDetailsContentViewModel.showDetailsContent(expandable, null)
runCurrent()
verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean())
@@ -214,7 +214,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
@Test
fun testShowDetailsContent_animated_inDetailsView() {
testScope.runTest {
- bluetoothTileDialogViewModel.showDetailsContent(expandable, mockView)
+ bluetoothDetailsContentViewModel.showDetailsContent(expandable, mockView)
runCurrent()
verify(bluetoothDetailsContentManager).bind(mockView)
@@ -226,7 +226,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
fun testShowDetailsContent_animated_callInBackgroundThread() {
testScope.runTest {
backgroundExecutor.execute {
- bluetoothTileDialogViewModel.showDetailsContent(expandable, null)
+ bluetoothDetailsContentViewModel.showDetailsContent(expandable, null)
runCurrent()
verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean())
@@ -238,7 +238,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
fun testShowDetailsContent_animated_callInBackgroundThread_inDetailsView() {
testScope.runTest {
backgroundExecutor.execute {
- bluetoothTileDialogViewModel.showDetailsContent(expandable, mockView)
+ bluetoothDetailsContentViewModel.showDetailsContent(expandable, mockView)
runCurrent()
verify(bluetoothDetailsContentManager).bind(mockView)
@@ -250,7 +250,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
@Test
fun testShowDetailsContent_fetchDeviceItem() {
testScope.runTest {
- bluetoothTileDialogViewModel.showDetailsContent(null, null)
+ bluetoothDetailsContentViewModel.showDetailsContent(null, null)
runCurrent()
verify(deviceItemInteractor).deviceItemUpdate
@@ -261,11 +261,11 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
fun testStartSettingsActivity_activityLaunched_dialogDismissed() {
testScope.runTest {
whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
- bluetoothTileDialogViewModel.showDetailsContent(null, null)
+ bluetoothDetailsContentViewModel.showDetailsContent(null, null)
runCurrent()
val clickedView = View(context)
- bluetoothTileDialogViewModel.onPairNewDeviceClicked(clickedView)
+ bluetoothDetailsContentViewModel.onPairNewDeviceClicked(clickedView)
verify(uiEventLogger).log(BluetoothTileDialogUiEvent.PAIR_NEW_DEVICE_CLICKED)
verify(activityStarter).postStartActivityDismissingKeyguard(any(), anyInt(), nullable())
@@ -276,7 +276,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
fun testBuildUiProperties_bluetoothOn_shouldHideAutoOn() {
testScope.runTest {
val actual =
- BluetoothTileDialogViewModel.UiProperties.build(
+ BluetoothDetailsContentViewModel.UiProperties.build(
isBluetoothEnabled = true,
isAutoOnToggleFeatureAvailable = true,
)
@@ -288,7 +288,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
fun testBuildUiProperties_bluetoothOff_shouldShowAutoOn() {
testScope.runTest {
val actual =
- BluetoothTileDialogViewModel.UiProperties.build(
+ BluetoothDetailsContentViewModel.UiProperties.build(
isBluetoothEnabled = false,
isAutoOnToggleFeatureAvailable = true,
)
@@ -300,7 +300,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
fun testBuildUiProperties_bluetoothOff_autoOnFeatureUnavailable_shouldHideAutoOn() {
testScope.runTest {
val actual =
- BluetoothTileDialogViewModel.UiProperties.build(
+ BluetoothDetailsContentViewModel.UiProperties.build(
isBluetoothEnabled = false,
isAutoOnToggleFeatureAvailable = false,
)
@@ -313,7 +313,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
testScope.runTest {
whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(true)
- val actual = bluetoothTileDialogViewModel.isAutoOnToggleFeatureAvailable()
+ val actual = bluetoothDetailsContentViewModel.isAutoOnToggleFeatureAvailable()
assertThat(actual).isTrue()
}
}
@@ -323,7 +323,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
testScope.runTest {
whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(false)
- val actual = bluetoothTileDialogViewModel.isAutoOnToggleFeatureAvailable()
+ val actual = bluetoothDetailsContentViewModel.isAutoOnToggleFeatureAvailable()
assertThat(actual).isFalse()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt
index 2788f1d95382..7f75b8f03533 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt
@@ -80,7 +80,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() {
@Mock private lateinit var dialogTransitionAnimator: DialogTransitionAnimator
private val uiProperties =
- BluetoothTileDialogViewModel.UiProperties.build(
+ BluetoothDetailsContentViewModel.UiProperties.build(
isBluetoothEnabled = ENABLED,
isAutoOnToggleFeatureAvailable = ENABLED,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index 296a0fc2eb40..296a0fc2eb40 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogEulogizerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt
index ae6b337a3fa0..ae6b337a3fa0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogEulogizerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
index 6cb6fed978b8..6cb6fed978b8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 4ccfa29d4ba0..e8054c07eac8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -206,6 +206,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock ShadeInteractor mShadeInteractor;
private @Mock ShadeWindowLogger mShadeWindowLogger;
private @Mock SelectedUserInteractor mSelectedUserInteractor;
+ private @Mock UserTracker.Callback mUserTrackerCallback;
private @Mock KeyguardInteractor mKeyguardInteractor;
private @Mock KeyguardTransitionBootInteractor mKeyguardTransitionBootInteractor;
private @Captor ArgumentCaptor<KeyguardStateController.Callback>
@@ -280,7 +281,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
() -> mShadeInteractor,
mShadeWindowLogger,
() -> mSelectedUserInteractor,
- mUserTracker,
+ mock(UserTracker.class),
mKosmos.getNotificationShadeWindowModel(),
mSecureSettings,
mKosmos::getCommunalInteractor,
@@ -318,7 +319,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
} catch (Exception e) {
// Just so we don't have to add the exception signature to every test.
- fail();
+ fail(e.getMessage());
}
}
@@ -330,18 +331,156 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
/* First test the default behavior: handleUserSwitching() is not invoked */
when(mUserTracker.isUserSwitching()).thenReturn(false);
- mViewMediator.mUpdateCallback = mock(KeyguardUpdateMonitorCallback.class);
mViewMediator.onSystemReady();
TestableLooper.get(this).processAllMessages();
- verify(mViewMediator.mUpdateCallback, never()).onUserSwitching(userId);
+ verify(mUserTrackerCallback, never()).onUserChanging(eq(userId), eq(mContext),
+ any(Runnable.class));
/* Next test user switching is already in progress when started */
when(mUserTracker.isUserSwitching()).thenReturn(true);
mViewMediator.onSystemReady();
TestableLooper.get(this).processAllMessages();
- verify(mViewMediator.mUpdateCallback).onUserSwitching(userId);
+ verify(mUserTrackerCallback).onUserChanging(eq(userId), eq(mContext),
+ any(Runnable.class));
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void testGoingAwayFollowedByBeforeUserSwitchDoesNotHideKeyguard() {
+ setCurrentUser(/* userId= */1099, /* isSecure= */false);
+
+ // Setup keyguard
+ mViewMediator.onSystemReady();
+ processAllMessagesAndBgExecutorMessages();
+ mViewMediator.setShowingLocked(true, "");
+
+ // Request keyguard going away
+ when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
+ mViewMediator.mKeyguardGoingAwayRunnable.run();
+
+ // After the request, begin a switch to a new secure user
+ int nextUserId = 500;
+ setCurrentUser(nextUserId, /* isSecure= */true);
+ Runnable result = mock(Runnable.class);
+ mViewMediator.handleBeforeUserSwitching(nextUserId, result);
+ processAllMessagesAndBgExecutorMessages();
+ verify(result).run();
+
+ // After that request has begun, have WM tell us to exit keyguard
+ RemoteAnimationTarget[] apps = new RemoteAnimationTarget[]{
+ mock(RemoteAnimationTarget.class)
+ };
+ RemoteAnimationTarget[] wallpapers = new RemoteAnimationTarget[]{
+ mock(RemoteAnimationTarget.class)
+ };
+ IRemoteAnimationFinishedCallback callback = mock(IRemoteAnimationFinishedCallback.class);
+ mViewMediator.startKeyguardExitAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, apps, wallpapers,
+ null, callback);
+ processAllMessagesAndBgExecutorMessages();
+
+ // The call to exit should be rejected, and keyguard should still be visible
+ verify(mKeyguardUnlockAnimationController, never()).notifyStartSurfaceBehindRemoteAnimation(
+ any(), any(), any(), anyLong(), anyBoolean());
+ try {
+ assertATMSLockScreenShowing(true);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ assertTrue(mViewMediator.isShowingAndNotOccluded());
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void testUserSwitchToSecureUserShowsBouncer() {
+ setCurrentUser(/* userId= */1099, /* isSecure= */true);
+
+ // Setup keyguard
+ mViewMediator.onSystemReady();
+ processAllMessagesAndBgExecutorMessages();
+ mViewMediator.setShowingLocked(true, "");
+
+ // After the request, begin a switch to a new secure user
+ int nextUserId = 500;
+ setCurrentUser(nextUserId, /* isSecure= */true);
+
+ Runnable beforeResult = mock(Runnable.class);
+ mViewMediator.handleBeforeUserSwitching(nextUserId, beforeResult);
+ processAllMessagesAndBgExecutorMessages();
+ verify(beforeResult).run();
+
+ // Dismiss should not be called while user switch is in progress
+ Runnable onSwitchResult = mock(Runnable.class);
+ mViewMediator.handleUserSwitching(nextUserId, onSwitchResult);
+ processAllMessagesAndBgExecutorMessages();
+ verify(onSwitchResult).run();
+ verify(mStatusBarKeyguardViewManager, never()).dismissAndCollapse();
+
+ // The attempt to dismiss only comes on user switch complete, which will trigger a call to
+ // show the bouncer in StatusBarKeyguardViewManager
+ mViewMediator.handleUserSwitchComplete(nextUserId);
+ TestableLooper.get(this).moveTimeForward(600);
+ processAllMessagesAndBgExecutorMessages();
+
+ verify(mStatusBarKeyguardViewManager).dismissAndCollapse();
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void testUserSwitchToInsecureUserDismissesKeyguard() {
+ int userId = 1099;
+ when(mUserTracker.getUserId()).thenReturn(userId);
+
+ // Setup keyguard
+ mViewMediator.onSystemReady();
+ processAllMessagesAndBgExecutorMessages();
+ mViewMediator.setShowingLocked(true, "");
+
+ // After the request, begin a switch to an insecure user
+ int nextUserId = 500;
+ when(mLockPatternUtils.isSecure(nextUserId)).thenReturn(false);
+
+ Runnable beforeResult = mock(Runnable.class);
+ mViewMediator.handleBeforeUserSwitching(nextUserId, beforeResult);
+ processAllMessagesAndBgExecutorMessages();
+ verify(beforeResult).run();
+
+ // The call to dismiss comes during the user switch
+ Runnable onSwitchResult = mock(Runnable.class);
+ mViewMediator.handleUserSwitching(nextUserId, onSwitchResult);
+ processAllMessagesAndBgExecutorMessages();
+ verify(onSwitchResult).run();
+
+ verify(mStatusBarKeyguardViewManager).dismissAndCollapse();
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void testUserSwitchToSecureUserWhileKeyguardNotVisibleShowsKeyguard() {
+ setCurrentUser(/* userId= */1099, /* isSecure= */true);
+
+ // Setup keyguard as not visible
+ mViewMediator.onSystemReady();
+ processAllMessagesAndBgExecutorMessages();
+ mViewMediator.setShowingLocked(false, "");
+ processAllMessagesAndBgExecutorMessages();
+
+ // Begin a switch to a new secure user
+ int nextUserId = 500;
+ setCurrentUser(nextUserId, /* isSecure= */true);
+
+ Runnable beforeResult = mock(Runnable.class);
+ mViewMediator.handleBeforeUserSwitching(nextUserId, beforeResult);
+ processAllMessagesAndBgExecutorMessages();
+ verify(beforeResult).run();
+
+ try {
+ assertATMSLockScreenShowing(true);
+ } catch (Exception e) {
+ fail();
+ }
+ assertTrue(mViewMediator.isShowingAndNotOccluded());
}
@Test
@@ -1105,7 +1244,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
processAllMessagesAndBgExecutorMessages();
verify(mStatusBarKeyguardViewManager, never()).reset(anyBoolean());
- assertATMSAndKeyguardViewMediatorStatesMatch();
+
}
@Test
@@ -1149,6 +1288,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
IRemoteAnimationFinishedCallback callback = mock(IRemoteAnimationFinishedCallback.class);
when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
+ mViewMediator.mKeyguardGoingAwayRunnable.run();
mViewMediator.startKeyguardExitAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, apps, wallpapers,
null, callback);
processAllMessagesAndBgExecutorMessages();
@@ -1203,13 +1343,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
// The captor will have the most recent setLockScreenShown call's value.
assertEquals(showing, showingCaptor.getValue());
-
- // We're now just after the last setLockScreenShown call. If we expect the lockscreen to be
- // showing, ensure that we didn't subsequently ask for it to go away.
- if (showing) {
- orderedSetLockScreenShownCalls.verify(mActivityTaskManagerService, never())
- .keyguardGoingAway(anyInt());
- }
}
/**
@@ -1371,6 +1504,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mKeyguardTransitionBootInteractor,
mKosmos::getCommunalSceneInteractor,
mock(WindowManagerOcclusionManager.class));
+ mViewMediator.mUserChangedCallback = mUserTrackerCallback;
mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null);
@@ -1384,4 +1518,10 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private void captureKeyguardUpdateMonitorCallback() {
verify(mUpdateMonitor).registerCallback(mKeyguardUpdateMonitorCallbackCaptor.capture());
}
+
+ private void setCurrentUser(int userId, boolean isSecure) {
+ when(mUserTracker.getUserId()).thenReturn(userId);
+ when(mSelectedUserInteractor.getSelectedUserId()).thenReturn(userId);
+ when(mLockPatternUtils.isSecure(userId)).thenReturn(isSecure);
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt
index 9c7f01495b58..9c7f01495b58 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/HydratorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/HydratorTest.kt
index b0e93fbecbb9..b0e93fbecbb9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/HydratorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/HydratorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
index a2bd5ec28f08..aaf5559290df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
@@ -66,6 +66,7 @@ import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.setSceneTransition
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.statusbar.featurepods.media.domain.interactor.mediaControlChipInteractor
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -203,6 +204,7 @@ class MediaCarouselControllerTest(flags: FlagsParameterization) : SysuiTestCase(
mediaCarouselViewModel = kosmos.mediaCarouselViewModel,
mediaViewControllerFactory = mediaViewControllerFactory,
deviceEntryInteractor = kosmos.deviceEntryInteractor,
+ mediaControlChipInteractor = kosmos.mediaControlChipInteractor,
)
verify(configurationController).addCallback(capture(configListener))
verify(visualStabilityProvider)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 23282b16d8a8..205ccea657df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -84,7 +84,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
private final Kosmos mKosmos = SysuiTestCaseExtKt.testKosmos(this);
// Mock
- private MediaOutputBaseAdapter mMediaOutputBaseAdapter = mock(MediaOutputBaseAdapter.class);
+ private MediaOutputAdapterBase mMediaOutputBaseAdapter = mock(MediaOutputAdapterBase.class);
private MediaController mMediaController = mock(MediaController.class);
private PlaybackState mPlaybackState = mock(PlaybackState.class);
private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
@@ -219,7 +219,6 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
public void refresh_withIconCompat_iconIsVisible() {
mIconCompat = IconCompat.createWithBitmap(
Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888));
- when(mMediaOutputBaseAdapter.getController()).thenReturn(mMediaSwitchingController);
mMediaOutputBaseDialogImpl.refresh();
final ImageView view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/QSFragmentComposeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/QSFragmentComposeTest.kt
index ab78029684d4..ab78029684d4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/QSFragmentComposeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/QSFragmentComposeTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
index 26cf4a261289..92b26ea3a8ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
@@ -22,14 +22,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
-import androidx.compose.ui.semantics.SemanticsProperties
-import androidx.compose.ui.test.SemanticsMatcher
-import androidx.compose.ui.test.assert
-import androidx.compose.ui.test.filter
-import androidx.compose.ui.test.hasContentDescription
-import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onChildren
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
@@ -100,7 +93,10 @@ class DragAndDropTest : SysuiTestCase() {
composeRule.onNodeWithText("Remove").assertExists()
// Every other tile should still be in the same order
- composeRule.assertTileGridContainsExactly(listOf("tileB", "tileC", "tileD_large", "tileE"))
+ composeRule.assertGridContainsExactly(
+ CURRENT_TILES_GRID_TEST_TAG,
+ listOf("tileB", "tileC", "tileD_large", "tileE"),
+ )
}
@Test
@@ -125,8 +121,9 @@ class DragAndDropTest : SysuiTestCase() {
composeRule.onNodeWithText("Remove").assertDoesNotExist()
// Tile A and B should swap places
- composeRule.assertTileGridContainsExactly(
- listOf("tileB", "tileA", "tileC", "tileD_large", "tileE")
+ composeRule.assertGridContainsExactly(
+ CURRENT_TILES_GRID_TEST_TAG,
+ listOf("tileB", "tileA", "tileC", "tileD_large", "tileE"),
)
}
@@ -152,7 +149,10 @@ class DragAndDropTest : SysuiTestCase() {
composeRule.onNodeWithText("Remove").assertDoesNotExist()
// Tile A is gone
- composeRule.assertTileGridContainsExactly(listOf("tileB", "tileC", "tileD_large", "tileE"))
+ composeRule.assertGridContainsExactly(
+ CURRENT_TILES_GRID_TEST_TAG,
+ listOf("tileB", "tileC", "tileD_large", "tileE"),
+ )
}
@Test
@@ -166,7 +166,7 @@ class DragAndDropTest : SysuiTestCase() {
}
composeRule.waitForIdle()
- listState.onStarted(createEditTile("newTile"), DragType.Add)
+ listState.onStarted(createEditTile("tile_new"), DragType.Add)
// Insert after tileD, which is at index 4
// [ a ] [ b ] [ c ] [ empty ]
// [ tile d ] [ e ]
@@ -179,23 +179,13 @@ class DragAndDropTest : SysuiTestCase() {
// Remove drop zone should disappear
composeRule.onNodeWithText("Remove").assertDoesNotExist()
- // newTile is added after tileD
- composeRule.assertTileGridContainsExactly(
- listOf("tileA", "tileB", "tileC", "tileD_large", "newTile", "tileE")
+ // tile_new is added after tileD
+ composeRule.assertGridContainsExactly(
+ CURRENT_TILES_GRID_TEST_TAG,
+ listOf("tileA", "tileB", "tileC", "tileD_large", "tile_new", "tileE"),
)
}
- private fun ComposeContentTestRule.assertTileGridContainsExactly(specs: List<String>) {
- onNodeWithTag(CURRENT_TILES_GRID_TEST_TAG)
- .onChildren()
- .filter(SemanticsMatcher.keyIsDefined(SemanticsProperties.ContentDescription))
- .apply {
- fetchSemanticsNodes().forEachIndexed { index, _ ->
- get(index).assert(hasContentDescription(specs[index]))
- }
- }
- }
-
companion object {
private const val CURRENT_TILES_GRID_TEST_TAG = "CurrentTilesGrid"
private const val AVAILABLE_TILES_GRID_TEST_TAG = "AvailableTilesGrid"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt
index 4e8b0bcd374c..8c09b81744d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt
@@ -23,16 +23,9 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
-import androidx.compose.ui.semantics.SemanticsProperties
-import androidx.compose.ui.test.SemanticsMatcher
-import androidx.compose.ui.test.assert
-import androidx.compose.ui.test.filter
-import androidx.compose.ui.test.hasContentDescription
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onChildren
import androidx.compose.ui.test.onNodeWithContentDescription
-import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.text.AnnotatedString
@@ -113,20 +106,6 @@ class EditModeTest : SysuiTestCase() {
specs: List<String>
) = assertGridContainsExactly(AVAILABLE_TILES_GRID_TEST_TAG, specs)
- private fun ComposeContentTestRule.assertGridContainsExactly(
- testTag: String,
- specs: List<String>,
- ) {
- onNodeWithTag(testTag)
- .onChildren()
- .filter(SemanticsMatcher.keyIsDefined(SemanticsProperties.ContentDescription))
- .apply {
- fetchSemanticsNodes().forEachIndexed { index, _ ->
- get(index).assert(hasContentDescription(specs[index]))
- }
- }
- }
-
companion object {
private const val CURRENT_TILES_GRID_TEST_TAG = "CurrentTilesGrid"
private const val AVAILABLE_TILES_GRID_TEST_TAG = "AvailableTilesGrid"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/TestMatchers.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/TestMatchers.kt
new file mode 100644
index 000000000000..dbccf864fc26
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/TestMatchers.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.ui.compose
+
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.semantics.getOrNull
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.filter
+import androidx.compose.ui.test.hasContentDescription
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.onChildren
+import androidx.compose.ui.test.onNodeWithTag
+
+/** Asserts that the tile grid with [testTag] contains exactly [specs] */
+fun ComposeContentTestRule.assertGridContainsExactly(testTag: String, specs: List<String>) {
+ onNodeWithTag(testTag)
+ .onChildren()
+ .filter(SemanticsMatcher.contentDescriptionStartsWith("tile"))
+ .apply {
+ fetchSemanticsNodes().forEachIndexed { index, _ ->
+ get(index).assert(hasContentDescription(specs[index]))
+ }
+ }
+}
+
+/**
+ * A [SemanticsMatcher] that matches anything with a content description starting with the given
+ * [prefix]
+ */
+fun SemanticsMatcher.Companion.contentDescriptionStartsWith(prefix: String): SemanticsMatcher {
+ return SemanticsMatcher("${SemanticsProperties.ContentDescription.name} starts with $prefix") {
+ semanticsNode ->
+ semanticsNode.config.getOrNull(SemanticsProperties.ContentDescription)?.any {
+ it.startsWith(prefix)
+ } ?: false
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
index 1305b0c4c499..cfe34f446f36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
@@ -16,7 +16,7 @@ import com.android.internal.telephony.flags.Flags
import com.android.settingslib.Utils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.systemui.SysuiTestCase
-import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogViewModel
+import com.android.systemui.bluetooth.qsdialog.BluetoothDetailsContentViewModel
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.plugins.ActivityStarter
@@ -71,7 +71,7 @@ class BluetoothTileTest(flags: FlagsParameterization) : SysuiTestCase() {
@Mock private lateinit var bluetoothController: BluetoothController
@Mock private lateinit var uiEventLogger: QsEventLogger
@Mock private lateinit var featureFlags: FeatureFlagsClassic
- @Mock private lateinit var bluetoothTileDialogViewModel: BluetoothTileDialogViewModel
+ @Mock private lateinit var bluetoothDetailsContentViewModel: BluetoothDetailsContentViewModel
@Mock private lateinit var clickJob: Job
private lateinit var testableLooper: TestableLooper
private lateinit var tile: FakeBluetoothTile
@@ -96,7 +96,7 @@ class BluetoothTileTest(flags: FlagsParameterization) : SysuiTestCase() {
qsLogger,
bluetoothController,
featureFlags,
- bluetoothTileDialogViewModel,
+ bluetoothDetailsContentViewModel,
)
tile.initialize()
@@ -238,7 +238,7 @@ class BluetoothTileTest(flags: FlagsParameterization) : SysuiTestCase() {
tile.handleClick(null)
- verify(bluetoothTileDialogViewModel)
+ verify(bluetoothDetailsContentViewModel)
.showDetailsContent(/* expandable= */ null, /* view= */ null)
}
@@ -308,7 +308,7 @@ class BluetoothTileTest(flags: FlagsParameterization) : SysuiTestCase() {
qsLogger: QSLogger,
bluetoothController: BluetoothController,
featureFlags: FeatureFlagsClassic,
- bluetoothTileDialogViewModel: BluetoothTileDialogViewModel,
+ bluetoothDetailsContentViewModel: BluetoothDetailsContentViewModel,
) :
BluetoothTile(
qsHost,
@@ -322,7 +322,7 @@ class BluetoothTileTest(flags: FlagsParameterization) : SysuiTestCase() {
qsLogger,
bluetoothController,
featureFlags,
- bluetoothTileDialogViewModel,
+ bluetoothDetailsContentViewModel,
) {
var restrictionChecked: String? = null
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
index 1a4749c3196c..1a4749c3196c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 944604f94ce4..ae8b52aa6553 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -18,7 +18,7 @@ package com.android.systemui.shade
import android.graphics.Insets
import android.graphics.Rect
-import android.os.PowerManager
+import android.os.powerManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
@@ -32,7 +32,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.SceneKey
-import com.android.systemui.Flags
+import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX
import com.android.systemui.SysuiTestCase
@@ -40,7 +40,6 @@ import com.android.systemui.ambient.touch.TouchHandler
import com.android.systemui.ambient.touch.TouchMonitor
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
-import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
@@ -58,8 +57,10 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.media.controls.controller.keyguardMediaController
import com.android.systemui.res.R
@@ -69,8 +70,8 @@ import com.android.systemui.statusbar.lockscreen.lockscreenSmartspaceController
import com.android.systemui.statusbar.notification.stack.notificationStackScrollLayoutController
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Assert.assertThrows
@@ -89,33 +90,23 @@ import org.mockito.kotlin.whenever
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
+@EnableFlags(FLAG_COMMUNAL_HUB)
class GlanceableHubContainerControllerTest : SysuiTestCase() {
- private val kosmos: Kosmos =
- testKosmos().apply {
- // UnconfinedTestDispatcher makes testing simpler due to CommunalInteractor flows using
- // SharedFlow
- testDispatcher = UnconfinedTestDispatcher()
- }
+ private val kosmos: Kosmos = testKosmos().useUnconfinedTestDispatcher()
- private var communalViewModel = mock<CommunalViewModel>()
- private var powerManager = mock<PowerManager>()
- private var touchMonitor = mock<TouchMonitor>()
- private var communalColors = mock<CommunalColors>()
- private var communalContent = mock<CommunalContent>()
- private lateinit var ambientTouchComponentFactory: AmbientTouchComponent.Factory
+ private val swipeToHubEnabled = MutableStateFlow(false)
+ private val mockCommunalViewModel =
+ mock<CommunalViewModel> { on { swipeToHubEnabled } doReturn swipeToHubEnabled }
+ private val touchMonitor = mock<TouchMonitor>()
private lateinit var parentView: FrameLayout
private lateinit var containerView: View
- private lateinit var testableLooper: TestableLooper
-
- private lateinit var communalRepository: FakeCommunalSceneRepository
- private lateinit var underTest: GlanceableHubContainerController
- @Before
- fun setUp() {
- communalRepository = kosmos.fakeCommunalSceneRepository
+ private val Kosmos.testableLooper by
+ Kosmos.Fixture { TestableLooper.get(this@GlanceableHubContainerControllerTest) }
- ambientTouchComponentFactory =
+ private val Kosmos.ambientTouchComponentFactory by
+ Kosmos.Fixture {
object : AmbientTouchComponent.Factory {
override fun create(
lifecycleOwner: LifecycleOwner,
@@ -126,50 +117,39 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
override fun getTouchMonitor(): TouchMonitor = touchMonitor
}
}
+ }
- with(kosmos) {
- underTest =
- GlanceableHubContainerController(
- communalInteractor,
- communalSettingsInteractor,
- communalViewModel,
- keyguardInteractor,
- keyguardTransitionInteractor,
- shadeInteractor,
- powerManager,
- communalColors,
- ambientTouchComponentFactory,
- communalContent,
- sceneDataSourceDelegator,
- notificationStackScrollLayoutController,
- keyguardMediaController,
- lockscreenSmartspaceController,
- logcatLogBuffer("GlanceableHubContainerControllerTest"),
- )
-
- // Make below last notification true by default or else touches will be ignored by
- // default when the hub is not showing.
- whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
- .thenReturn(true)
+ private val Kosmos.underTest by
+ Kosmos.Fixture {
+ GlanceableHubContainerController(
+ communalInteractor,
+ communalSettingsInteractor,
+ mockCommunalViewModel,
+ keyguardInteractor,
+ keyguardTransitionInteractor,
+ shadeInteractor,
+ powerManager,
+ mock<CommunalColors>(),
+ ambientTouchComponentFactory,
+ mock<CommunalContent>(),
+ sceneDataSourceDelegator,
+ notificationStackScrollLayoutController,
+ keyguardMediaController,
+ lockscreenSmartspaceController,
+ logcatLogBuffer("GlanceableHubContainerControllerTest"),
+ )
}
- testableLooper = TestableLooper.get(this)
+ @Before
+ fun setUp() {
overrideResource(R.dimen.communal_right_edge_swipe_region_width, RIGHT_SWIPE_REGION_WIDTH)
overrideResource(R.dimen.communal_top_edge_swipe_region_height, TOP_SWIPE_REGION_WIDTH)
overrideResource(
R.dimen.communal_bottom_edge_swipe_region_height,
BOTTOM_SWIPE_REGION_WIDTH,
)
-
- // Make communal available so that communalInteractor.desiredScene accurately reflects
- // scene changes instead of just returning Blank.
- mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB)
- with(kosmos.testScope) {
- launch { kosmos.setCommunalAvailable(true) }
- testScheduler.runCurrent()
- }
-
- initAndAttachContainerView()
+ runBlocking { kosmos.setCommunalAvailable(true) }
+ kosmos.initAndAttachContainerView()
}
@After
@@ -179,606 +159,531 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
@Test
fun initView_calledTwice_throwsException() =
- with(kosmos) {
- testScope.runTest {
- underTest =
- GlanceableHubContainerController(
- communalInteractor,
- kosmos.communalSettingsInteractor,
- communalViewModel,
- keyguardInteractor,
- kosmos.keyguardTransitionInteractor,
- shadeInteractor,
- powerManager,
- communalColors,
- ambientTouchComponentFactory,
- communalContent,
- kosmos.sceneDataSourceDelegator,
- kosmos.notificationStackScrollLayoutController,
- kosmos.keyguardMediaController,
- kosmos.lockscreenSmartspaceController,
- logcatLogBuffer("GlanceableHubContainerControllerTest"),
- )
+ kosmos.runTest {
+ val controller =
+ GlanceableHubContainerController(
+ communalInteractor,
+ communalSettingsInteractor,
+ mockCommunalViewModel,
+ keyguardInteractor,
+ keyguardTransitionInteractor,
+ shadeInteractor,
+ powerManager,
+ mock<CommunalColors>(),
+ ambientTouchComponentFactory,
+ mock<CommunalContent>(),
+ sceneDataSourceDelegator,
+ notificationStackScrollLayoutController,
+ keyguardMediaController,
+ lockscreenSmartspaceController,
+ logcatLogBuffer("GlanceableHubContainerControllerTest"),
+ )
- // First call succeeds.
- underTest.initView(context)
+ // First call succeeds.
+ controller.initView(context)
- // Second call throws.
- assertThrows(RuntimeException::class.java) { underTest.initView(context) }
- }
+ // Second call throws.
+ assertThrows(RuntimeException::class.java) { controller.initView(context) }
}
@Test
fun lifecycle_initializedAfterConstruction() =
- with(kosmos) {
- val underTest =
+ kosmos.runTest {
+ val controller =
GlanceableHubContainerController(
communalInteractor,
- kosmos.communalSettingsInteractor,
- communalViewModel,
+ communalSettingsInteractor,
+ mockCommunalViewModel,
keyguardInteractor,
- kosmos.keyguardTransitionInteractor,
+ keyguardTransitionInteractor,
shadeInteractor,
powerManager,
- communalColors,
+ mock<CommunalColors>(),
ambientTouchComponentFactory,
- communalContent,
- kosmos.sceneDataSourceDelegator,
- kosmos.notificationStackScrollLayoutController,
- kosmos.keyguardMediaController,
- kosmos.lockscreenSmartspaceController,
+ mock<CommunalContent>(),
+ sceneDataSourceDelegator,
+ notificationStackScrollLayoutController,
+ keyguardMediaController,
+ lockscreenSmartspaceController,
logcatLogBuffer("GlanceableHubContainerControllerTest"),
)
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED)
+ assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED)
}
@Test
fun lifecycle_createdAfterViewCreated() =
- with(kosmos) {
- val underTest =
+ kosmos.runTest {
+ val controller =
GlanceableHubContainerController(
communalInteractor,
- kosmos.communalSettingsInteractor,
- communalViewModel,
+ communalSettingsInteractor,
+ mockCommunalViewModel,
keyguardInteractor,
- kosmos.keyguardTransitionInteractor,
+ keyguardTransitionInteractor,
shadeInteractor,
powerManager,
- communalColors,
+ mock<CommunalColors>(),
ambientTouchComponentFactory,
- communalContent,
- kosmos.sceneDataSourceDelegator,
- kosmos.notificationStackScrollLayoutController,
- kosmos.keyguardMediaController,
- kosmos.lockscreenSmartspaceController,
+ mock<CommunalContent>(),
+ sceneDataSourceDelegator,
+ notificationStackScrollLayoutController,
+ keyguardMediaController,
+ lockscreenSmartspaceController,
logcatLogBuffer("GlanceableHubContainerControllerTest"),
)
// Only initView without attaching a view as we don't want the flows to start collecting
// yet.
- underTest.initView(View(context))
+ controller.initView(View(context))
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED)
+ assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED)
}
@Test
- fun lifecycle_startedAfterFlowsUpdate() {
- // Flows start collecting due to test setup, causing the state to advance to STARTED.
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ fun lifecycle_startedAfterFlowsUpdate() =
+ kosmos.runTest {
+ // Flows start collecting due to test setup, causing the state to advance to STARTED.
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
+ }
@Test
fun lifecycle_resumedAfterCommunalShows() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
}
@Test
fun lifecycle_startedAfterCommunalCloses() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
- // Communal closes.
- goToScene(CommunalScenes.Blank)
+ // Communal closes.
+ goToScene(CommunalScenes.Blank)
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_startedAfterPrimaryBouncerShows() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- // Bouncer is visible.
- fakeKeyguardBouncerRepository.setPrimaryShow(true)
- testableLooper.processAllMessages()
+ // Bouncer is visible.
+ fakeKeyguardBouncerRepository.setPrimaryShow(true)
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_startedAfterAlternateBouncerShows() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- // Bouncer is visible.
- fakeKeyguardBouncerRepository.setAlternateVisible(true)
- testableLooper.processAllMessages()
+ // Bouncer is visible.
+ fakeKeyguardBouncerRepository.setAlternateVisible(true)
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_startedWhenEditActivityShowing() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- // Edit activity is showing.
- communalInteractor.setEditActivityShowing(true)
- testableLooper.processAllMessages()
+ // Edit activity is showing.
+ communalInteractor.setEditActivityShowing(true)
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_startedWhenEditModeTransitionStarted() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Leaving edit mode to return to the hub.
- fakeKeyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.GLANCEABLE_HUB,
- value = 1.0f,
- transitionState = TransitionState.RUNNING,
- )
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Leaving edit mode to return to the hub.
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.GLANCEABLE_HUB,
+ value = 1.0f,
+ transitionState = TransitionState.RUNNING,
)
- testableLooper.processAllMessages()
+ )
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
- fun lifecycle_createdAfterDisposeView() {
- // Container view disposed.
- underTest.disposeView()
+ fun lifecycle_createdAfterDisposeView() =
+ kosmos.runTest {
+ // Container view disposed.
+ underTest.disposeView()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED)
+ }
@Test
fun lifecycle_startedAfterShadeShows() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
- // Shade shows up.
- shadeTestUtil.setQsExpansion(1.0f)
- testableLooper.processAllMessages()
+ // Shade shows up.
+ shadeTestUtil.setQsExpansion(1.0f)
+ testableLooper.processAllMessages()
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
- }
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
}
@Test
fun lifecycle_doesNotResumeOnUserInteractivityOnceExpanded() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Shade shows up.
- shadeTestUtil.setShadeExpansion(1.0f)
- testableLooper.processAllMessages()
- underTest.onTouchEvent(DOWN_EVENT)
- testableLooper.processAllMessages()
-
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
-
- // Shade starts collapsing.
- shadeTestUtil.setShadeExpansion(.5f)
- testableLooper.processAllMessages()
- underTest.onTouchEvent(DOWN_EVENT)
- testableLooper.processAllMessages()
-
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
-
- // Shade fully collpase, and then expand should with touch interaction should now
- // be resumed.
- shadeTestUtil.setShadeExpansion(0f)
- testableLooper.processAllMessages()
- shadeTestUtil.setShadeExpansion(.5f)
- testableLooper.processAllMessages()
- underTest.onTouchEvent(DOWN_EVENT)
- testableLooper.processAllMessages()
-
- assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
- }
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Shade shows up.
+ shadeTestUtil.setShadeExpansion(1.0f)
+ testableLooper.processAllMessages()
+ underTest.onTouchEvent(DOWN_EVENT)
+ testableLooper.processAllMessages()
+
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
+
+ // Shade starts collapsing.
+ shadeTestUtil.setShadeExpansion(.5f)
+ testableLooper.processAllMessages()
+ underTest.onTouchEvent(DOWN_EVENT)
+ testableLooper.processAllMessages()
+
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED)
+
+ // Shade fully collpase, and then expand should with touch interaction should now
+ // be resumed.
+ shadeTestUtil.setShadeExpansion(0f)
+ testableLooper.processAllMessages()
+ shadeTestUtil.setShadeExpansion(.5f)
+ testableLooper.processAllMessages()
+ underTest.onTouchEvent(DOWN_EVENT)
+ testableLooper.processAllMessages()
+
+ assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
}
@Test
fun touchHandling_moveEventProcessedAfterCancel() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Touch starts and ends.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
- assertThat(underTest.onTouchEvent(CANCEL_EVENT)).isTrue()
-
- // Up event is no longer processed
- assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
-
- // Move event can still be processed
- assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
- assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
- assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
- }
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Touch starts and ends.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(CANCEL_EVENT)).isTrue()
+
+ // Up event is no longer processed
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
+
+ // Move event can still be processed
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
}
@Test
fun editMode_communalAvailable() =
- with(kosmos) {
- testScope.runTest {
- val available by collectLastValue(underTest.communalAvailable())
- setCommunalAvailable(false)
-
- assertThat(available).isFalse()
- communalInteractor.setEditModeOpen(true)
- assertThat(available).isTrue()
- }
+ kosmos.runTest {
+ val available by collectLastValue(underTest.communalAvailable())
+ setCommunalAvailable(false)
+
+ assertThat(available).isFalse()
+ communalInteractor.setEditModeOpen(true)
+ assertThat(available).isTrue()
}
@Test
@DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_setAfterInit() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
-
- assertThat(containerView.systemGestureExclusionRects)
- .containsExactly(
- Rect(
- /* left= */ 0,
- /* top= */ TOP_SWIPE_REGION_WIDTH,
- /* right= */ CONTAINER_WIDTH,
- /* bottom= */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH,
- )
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
+
+ assertThat(containerView.systemGestureExclusionRects)
+ .containsExactly(
+ Rect(
+ /* left= */ 0,
+ /* top= */ TOP_SWIPE_REGION_WIDTH,
+ /* right= */ CONTAINER_WIDTH,
+ /* bottom= */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH,
)
- }
+ )
}
@Test
@EnableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_setAfterInit_fullSwipe() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
- assertThat(containerView.systemGestureExclusionRects).isEmpty()
- }
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
}
@Test
@DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_unsetWhenShadeOpen() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
- // Exclusion rect is set.
- assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
+ // Exclusion rect is set.
+ assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
- // Shade shows up.
- shadeTestUtil.setQsExpansion(1.0f)
- testableLooper.processAllMessages()
+ // Shade shows up.
+ shadeTestUtil.setQsExpansion(1.0f)
+ testableLooper.processAllMessages()
- // Exclusion rects are unset.
- assertThat(containerView.systemGestureExclusionRects).isEmpty()
- }
+ // Exclusion rects are unset.
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
}
@Test
@DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_unsetWhenBouncerOpen() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
- // Exclusion rect is set.
- assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
+ // Exclusion rect is set.
+ assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
- // Bouncer is visible.
- fakeKeyguardBouncerRepository.setPrimaryShow(true)
- testableLooper.processAllMessages()
+ // Bouncer is visible.
+ fakeKeyguardBouncerRepository.setPrimaryShow(true)
+ testableLooper.processAllMessages()
- // Exclusion rects are unset.
- assertThat(containerView.systemGestureExclusionRects).isEmpty()
- }
+ // Exclusion rects are unset.
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
}
@Test
@DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
fun gestureExclusionZone_unsetWhenHubClosed() =
- with(kosmos) {
- testScope.runTest {
- goToScene(CommunalScenes.Communal)
+ kosmos.runTest {
+ goToScene(CommunalScenes.Communal)
- // Exclusion rect is set.
- assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
+ // Exclusion rect is set.
+ assertThat(containerView.systemGestureExclusionRects).isNotEmpty()
- // Leave the hub.
- goToScene(CommunalScenes.Blank)
+ // Leave the hub.
+ goToScene(CommunalScenes.Blank)
- // Exclusion rect is unset.
- assertThat(containerView.systemGestureExclusionRects).isEmpty()
- }
+ // Exclusion rect is unset.
+ assertThat(containerView.systemGestureExclusionRects).isEmpty()
}
@Test
fun fullScreenSwipeGesture_doNotProcessTouchesInNotificationStack() =
- with(kosmos) {
- testScope.runTest {
- // Communal is closed.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(false)
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- }
+ kosmos.runTest {
+ // Communal is closed.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(false)
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
}
@Test
fun fullScreenSwipeGesture_doNotProcessTouchesInUmo() =
- with(kosmos) {
- testScope.runTest {
- // Communal is closed.
- goToScene(CommunalScenes.Blank)
- whenever(keyguardMediaController.isWithinMediaViewBounds(any(), any()))
- .thenReturn(true)
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- }
+ kosmos.runTest {
+ // Communal is closed.
+ goToScene(CommunalScenes.Blank)
+ whenever(keyguardMediaController.isWithinMediaViewBounds(any(), any())).thenReturn(true)
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
}
@Test
fun fullScreenSwipeGesture_doNotProcessTouchesInSmartspace() =
- with(kosmos) {
- testScope.runTest {
- // Communal is closed.
- goToScene(CommunalScenes.Blank)
- whenever(lockscreenSmartspaceController.isWithinSmartspaceBounds(any(), any()))
- .thenReturn(true)
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- }
+ kosmos.runTest {
+ // Communal is closed.
+ goToScene(CommunalScenes.Blank)
+ whenever(lockscreenSmartspaceController.isWithinSmartspaceBounds(any(), any()))
+ .thenReturn(true)
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
}
@Test
fun onTouchEvent_hubOpen_touchesDispatched() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Touch event is sent to the container view.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
- verify(containerView).onTouchEvent(DOWN_EVENT)
- assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
- verify(containerView).onTouchEvent(UP_EVENT)
- }
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Touch event is sent to the container view.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ verify(containerView).onTouchEvent(DOWN_EVENT)
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
+ verify(containerView).onTouchEvent(UP_EVENT)
}
@Test
fun onTouchEvent_editActivityShowing_touchesConsumedButNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Transitioning to or from edit mode.
- communalInteractor.setEditActivityShowing(true)
- testableLooper.processAllMessages()
-
- // onTouchEvent returns true to consume the touch, but it is not sent to the
- // container view.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
- verify(containerView, never()).onTouchEvent(any())
- }
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Transitioning to or from edit mode.
+ communalInteractor.setEditActivityShowing(true)
+ testableLooper.processAllMessages()
+
+ // onTouchEvent returns true to consume the touch, but it is not sent to the
+ // container view.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ verify(containerView, never()).onTouchEvent(any())
}
@Test
fun onTouchEvent_editModeTransitionStarted_touchesConsumedButNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- // Communal is open.
- goToScene(CommunalScenes.Communal)
-
- // Leaving edit mode to return to the hub.
- fakeKeyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.GONE,
- to = KeyguardState.GLANCEABLE_HUB,
- value = 1.0f,
- transitionState = TransitionState.RUNNING,
- )
+ kosmos.runTest {
+ // Communal is open.
+ goToScene(CommunalScenes.Communal)
+
+ // Leaving edit mode to return to the hub.
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.GLANCEABLE_HUB,
+ value = 1.0f,
+ transitionState = TransitionState.RUNNING,
)
- testableLooper.processAllMessages()
+ )
+ testableLooper.processAllMessages()
- // onTouchEvent returns true to consume the touch, but it is not sent to the
- // container view.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
- verify(containerView, never()).onTouchEvent(any())
- }
+ // onTouchEvent returns true to consume the touch, but it is not sent to the
+ // container view.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ verify(containerView, never()).onTouchEvent(any())
}
@Test
fun onTouchEvent_shadeInteracting_movesNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- `whenever`(communalViewModel.swipeToHubEnabled()).thenReturn(true)
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(true)
+ kosmos.runTest {
+ swipeToHubEnabled.value = true
- // Touches not consumed by default but are received by containerView.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView).onTouchEvent(DOWN_EVENT)
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(true)
- // User is interacting with shade on lockscreen.
- shadeTestUtil.setLockscreenShadeTracking(true)
- testableLooper.processAllMessages()
+ // Touches not consumed by default but are received by containerView.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView).onTouchEvent(DOWN_EVENT)
- // A move event is ignored while the user is already interacting.
- assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(MOVE_EVENT)
+ // User is interacting with shade on lockscreen.
+ shadeTestUtil.setLockscreenShadeTracking(true)
+ testableLooper.processAllMessages()
- // An up event is still delivered.
- assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
- verify(containerView).onTouchEvent(UP_EVENT)
- }
+ // A move event is ignored while the user is already interacting.
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(MOVE_EVENT)
+
+ // An up event is still delivered.
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
+ verify(containerView).onTouchEvent(UP_EVENT)
}
@Test
fun onTouchEvent_shadeExpanding_touchesNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(true)
+ kosmos.runTest {
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(true)
- // Shade is open slightly.
- shadeTestUtil.setShadeExpansion(0.01f)
- testableLooper.processAllMessages()
+ // Shade is open slightly.
+ shadeTestUtil.setShadeExpansion(0.01f)
+ testableLooper.processAllMessages()
- // Touches are not consumed.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(DOWN_EVENT)
- }
+ // Touches are not consumed.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(DOWN_EVENT)
}
@Test
fun onTouchEvent_qsExpanding_touchesNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(true)
+ kosmos.runTest {
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(true)
- // Shade is open slightly.
- shadeTestUtil.setQsExpansion(0.01f)
- testableLooper.processAllMessages()
+ // Shade is open slightly.
+ shadeTestUtil.setQsExpansion(0.01f)
+ testableLooper.processAllMessages()
- // Touches are not consumed.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(DOWN_EVENT)
- }
+ // Touches are not consumed.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(DOWN_EVENT)
}
@Test
fun onTouchEvent_bouncerInteracting_movesNotDispatched() =
- with(kosmos) {
- testScope.runTest {
- `whenever`(communalViewModel.swipeToHubEnabled()).thenReturn(true)
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
- whenever(
- notificationStackScrollLayoutController.isBelowLastNotification(
- any(),
- any(),
- )
- )
- .thenReturn(true)
+ kosmos.runTest {
+ swipeToHubEnabled.value = true
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
+ whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any()))
+ .thenReturn(true)
- // Touches not consumed by default but are received by containerView.
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView).onTouchEvent(DOWN_EVENT)
+ // Touches not consumed by default but are received by containerView.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView).onTouchEvent(DOWN_EVENT)
- // User is interacting with bouncer on lockscreen.
- fakeKeyguardBouncerRepository.setPrimaryShow(true)
- testableLooper.processAllMessages()
+ // User is interacting with bouncer on lockscreen.
+ fakeKeyguardBouncerRepository.setPrimaryShow(true)
+ testableLooper.processAllMessages()
- // A move event is ignored while the user is already interacting.
- assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(MOVE_EVENT)
+ // A move event is ignored while the user is already interacting.
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(MOVE_EVENT)
- // An up event is still delivered.
- assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
- verify(containerView).onTouchEvent(UP_EVENT)
- }
+ // An up event is still delivered.
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
+ verify(containerView).onTouchEvent(UP_EVENT)
}
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
@Test
fun onTouchEvent_onLockscreenAndGlanceableHubV2_touchIgnored() =
- with(kosmos) {
- testScope.runTest {
- kosmos.setCommunalV2ConfigEnabled(true)
+ kosmos.runTest {
+ swipeToHubEnabled.value = false
+ setCommunalV2ConfigEnabled(true)
- // On lockscreen.
- goToScene(CommunalScenes.Blank)
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
- assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
- verify(containerView, never()).onTouchEvent(DOWN_EVENT)
- }
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(DOWN_EVENT)
}
@Test
- fun disposeView_destroysTouchMonitor() {
- clearInvocations(touchMonitor)
+ fun disposeView_destroysTouchMonitor() =
+ kosmos.runTest {
+ clearInvocations(touchMonitor)
- underTest.disposeView()
+ underTest.disposeView()
- verify(touchMonitor).destroy()
- }
+ verify(touchMonitor).destroy()
+ }
- private fun initAndAttachContainerView() {
+ private fun Kosmos.initAndAttachContainerView() {
val mockInsets =
mock<WindowInsets> {
on { getInsets(WindowInsets.Type.systemGestures()) } doReturn FAKE_INSETS
@@ -802,8 +707,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
testableLooper.processAllMessages()
}
- private suspend fun goToScene(scene: SceneKey) {
- communalRepository.changeScene(scene)
+ private suspend fun Kosmos.goToScene(scene: SceneKey) {
+ fakeCommunalSceneRepository.changeScene(scene)
if (scene == CommunalScenes.Communal) {
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
index 49cbb5a924f1..49cbb5a924f1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
index 89a3d5b5cf0b..89a3d5b5cf0b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
index e076418f2630..79e78c9532c6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
@@ -20,9 +20,10 @@ import android.view.LayoutInflater
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.app.animation.Interpolators
-import com.android.systemui.customization.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.FontVariationUtils
import com.android.systemui.animation.TextAnimator
+import com.android.systemui.customization.R
import com.android.systemui.util.mockito.any
import org.junit.Before
import org.junit.Rule
@@ -32,7 +33,9 @@ import org.mockito.Mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.eq
@RunWith(AndroidJUnit4::class)
@SmallTest
@@ -46,6 +49,7 @@ class AnimatableClockViewTest : SysuiTestCase() {
@Before
fun setUp() {
val layoutInflater = LayoutInflater.from(context)
+ whenever(mockTextAnimator.fontVariationUtils).thenReturn(FontVariationUtils())
clockView =
layoutInflater.inflate(R.layout.clock_default_small, null) as AnimatableClockView
clockView.textAnimatorFactory = { _, _ -> mockTextAnimator }
@@ -57,18 +61,19 @@ class AnimatableClockViewTest : SysuiTestCase() {
clockView.animateAppearOnLockscreen()
clockView.measure(50, 50)
+ verify(mockTextAnimator).fontVariationUtils
verify(mockTextAnimator).glyphFilter = any()
verify(mockTextAnimator)
.setTextStyle(
- weight = 300,
- textSize = -1.0f,
- color = 200,
- strokeWidth = -1F,
- animate = false,
- duration = 833L,
- interpolator = Interpolators.EMPHASIZED_DECELERATE,
- delay = 0L,
- onAnimationEnd = null
+ eq(TextAnimator.Style(fVar = "'wght' 300", color = 200)),
+ eq(
+ TextAnimator.Animation(
+ animate = false,
+ duration = 833L,
+ interpolator = Interpolators.EMPHASIZED_DECELERATE,
+ onAnimationEnd = null,
+ )
+ ),
)
verifyNoMoreInteractions(mockTextAnimator)
}
@@ -79,30 +84,24 @@ class AnimatableClockViewTest : SysuiTestCase() {
clockView.measure(50, 50)
clockView.animateAppearOnLockscreen()
+ verify(mockTextAnimator, times(2)).fontVariationUtils
verify(mockTextAnimator, times(2)).glyphFilter = any()
verify(mockTextAnimator)
.setTextStyle(
- weight = 100,
- textSize = -1.0f,
- color = 200,
- strokeWidth = -1F,
- animate = false,
- duration = 0L,
- interpolator = null,
- delay = 0L,
- onAnimationEnd = null
+ eq(TextAnimator.Style(fVar = "'wght' 100", color = 200)),
+ eq(TextAnimator.Animation(animate = false, duration = 0)),
)
+
verify(mockTextAnimator)
.setTextStyle(
- weight = 300,
- textSize = -1.0f,
- color = 200,
- strokeWidth = -1F,
- animate = true,
- duration = 833L,
- interpolator = Interpolators.EMPHASIZED_DECELERATE,
- delay = 0L,
- onAnimationEnd = null
+ eq(TextAnimator.Style(fVar = "'wght' 300", color = 200)),
+ eq(
+ TextAnimator.Animation(
+ animate = true,
+ duration = 833L,
+ interpolator = Interpolators.EMPHASIZED_DECELERATE,
+ )
+ ),
)
verifyNoMoreInteractions(mockTextAnimator)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
index 8418598c256b..8418598c256b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
index d67ce303c451..d67ce303c451 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
index fcbf0fe9a37a..510d6fe2b776 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
@@ -17,19 +17,23 @@
package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel
import android.platform.test.annotations.EnableFlags
+import androidx.compose.runtime.snapshots.Snapshot
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.lifecycle.activateIn
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel
-import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
+import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,22 +41,41 @@ import org.junit.runner.RunWith
@EnableFlags(StatusBarPopupChips.FLAG_NAME)
@RunWith(AndroidJUnit4::class)
class StatusBarPopupChipsViewModelTest : SysuiTestCase() {
- private val kosmos = testKosmos()
- private val testScope = kosmos.testScope
- private val mediaFilterRepository = kosmos.mediaFilterRepository
- private val underTest = kosmos.statusBarPopupChipsViewModel
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val underTest = kosmos.statusBarPopupChipsViewModelFactory.create()
+
+ @Before
+ fun setUp() {
+ underTest.activateIn(kosmos.testScope)
+ }
@Test
fun shownPopupChips_allHidden_empty() =
- testScope.runTest {
- val shownPopupChips by collectLastValue(underTest.shownPopupChips)
+ kosmos.runTest {
+ val shownPopupChips = underTest.shownPopupChips
assertThat(shownPopupChips).isEmpty()
}
@Test
fun shownPopupChips_activeMedia_restHidden_mediaControlChipShown() =
- testScope.runTest {
- val shownPopupChips by collectLastValue(underTest.shownPopupChips)
+ kosmos.runTest {
+ val shownPopupChips = underTest.shownPopupChips
+ val userMedia = MediaData(active = true, song = "test")
+ val instanceId = userMedia.instanceId
+
+ mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
+ mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+
+ Snapshot.takeSnapshot {
+ assertThat(shownPopupChips).hasSize(1)
+ assertThat(shownPopupChips.first().chipId).isEqualTo(PopupChipId.MediaControl)
+ }
+ }
+
+ @Test
+ fun shownPopupChips_mediaChipToggled_popupShown() =
+ kosmos.runTest {
+ val shownPopupChips = underTest.shownPopupChips
val userMedia = MediaData(active = true, song = "test")
val instanceId = userMedia.instanceId
@@ -60,7 +83,13 @@ class StatusBarPopupChipsViewModelTest : SysuiTestCase() {
mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
- assertThat(shownPopupChips).hasSize(1)
- assertThat(shownPopupChips!!.first().chipId).isEqualTo(PopupChipId.MediaControl)
+ Snapshot.takeSnapshot {
+ assertThat(shownPopupChips).hasSize(1)
+ val mediaChip = shownPopupChips.first()
+ assertThat(mediaChip.isPopupShown).isFalse()
+
+ mediaChip.showPopup.invoke()
+ assertThat(shownPopupChips.first().isPopupShown).isTrue()
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/layout/StatusBarBoundsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/layout/StatusBarBoundsProviderTest.kt
index 04319f05f6f9..04319f05f6f9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/layout/StatusBarBoundsProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/layout/StatusBarBoundsProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 281ce16b539f..19d1224a9bf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -28,6 +28,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -46,6 +48,7 @@ import android.os.Bundle;
import android.os.UserHandle;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
@@ -59,9 +62,12 @@ import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
@@ -83,6 +89,9 @@ public class NotificationEntryTest extends SysuiTestCase {
private NotificationChannel mChannel = Mockito.mock(NotificationChannel.class);
private final FakeSystemClock mClock = new FakeSystemClock();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setup() {
Notification.Builder n = new Notification.Builder(mContext, "")
@@ -444,6 +453,145 @@ public class NotificationEntryTest extends SysuiTestCase {
// no crash, good
}
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ public void getParent_adapter() {
+ GroupEntry ge = new GroupEntryBuilder()
+ .build();
+ Notification notification = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .build();
+
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setChannel(mChannel)
+ .setId(mId++)
+ .setNotification(notification)
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .setParent(ge)
+ .build();
+
+ assertThat(entry.getEntryAdapter().getParent()).isEqualTo(entry.getParent());
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ public void isTopLevelEntry_adapter() {
+ Notification notification = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .build();
+
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setChannel(mChannel)
+ .setId(mId++)
+ .setNotification(notification)
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .setParent(GroupEntry.ROOT_ENTRY)
+ .build();
+
+ assertThat(entry.getEntryAdapter().isTopLevelEntry()).isTrue();
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ public void getKey_adapter() {
+ Notification notification = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .build();
+
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setChannel(mChannel)
+ .setId(mId++)
+ .setNotification(notification)
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .build();
+
+ assertThat(entry.getEntryAdapter().getKey()).isEqualTo(entry.getKey());
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ public void getRow_adapter() {
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ Notification notification = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .build();
+
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setChannel(mChannel)
+ .setId(mId++)
+ .setNotification(notification)
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .build();
+ entry.setRow(row);
+
+ assertThat(entry.getEntryAdapter().getRow()).isEqualTo(entry.getRow());
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ public void getGroupRoot_adapter_groupSummary() {
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ Notification notification = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .setGroupSummary(true)
+ .setGroup("key")
+ .build();
+
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setChannel(mChannel)
+ .setId(mId++)
+ .setNotification(notification)
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .setParent(GroupEntry.ROOT_ENTRY)
+ .build();
+ entry.setRow(row);
+
+ assertThat(entry.getEntryAdapter().getGroupRoot()).isNull();
+ }
+
+ @Test
+ @EnableFlags(NotificationBundleUi.FLAG_NAME)
+ public void getGroupRoot_adapter_groupChild() {
+ Notification notification = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .setGroupSummary(true)
+ .setGroup("key")
+ .build();
+
+ NotificationEntry parent = new NotificationEntryBuilder()
+ .setParent(GroupEntry.ROOT_ENTRY)
+ .build();
+ GroupEntryBuilder groupEntry = new GroupEntryBuilder()
+ .setSummary(parent);
+
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setChannel(mChannel)
+ .setId(mId++)
+ .setNotification(notification)
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .setParent(groupEntry.build())
+ .build();
+
+ assertThat(entry.getEntryAdapter().getGroupRoot()).isEqualTo(parent.getEntryAdapter());
+ }
private Notification.Action createContextualAction(String title) {
return new Notification.Action.Builder(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index f1edb417a314..f1edb417a314 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt
index 99dcd6c9a798..99dcd6c9a798 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 77b116e2e465..a6722c5f4c22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static android.app.Flags.FLAG_NOTIFICATIONS_REDESIGN_TEMPLATES;
+
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL;
import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.PKG;
import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.USER_HANDLE;
@@ -29,6 +31,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -189,6 +192,54 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
}
@Test
+ @EnableFlags(FLAG_NOTIFICATIONS_REDESIGN_TEMPLATES)
+ public void setSensitive_doesNothingIfCalledAgain() throws Exception {
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ measureAndLayout(row);
+
+ // GIVEN a mocked public layout
+ NotificationContentView mockPublicLayout = mock(NotificationContentView.class);
+ row.setPublicLayout(mockPublicLayout);
+
+ // GIVEN a sensitive notification row that's currently redacted
+ row.setHideSensitiveForIntrinsicHeight(true);
+ row.setSensitive(true, true);
+ assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPublicLayout());
+ verify(mockPublicLayout).requestSelectLayout(eq(true));
+ clearInvocations(mockPublicLayout);
+
+ // WHEN the row is set to the same sensitive settings
+ row.setSensitive(true, true);
+
+ // VERIFY that the layout is not updated again
+ assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPublicLayout());
+ verify(mockPublicLayout, never()).requestSelectLayout(anyBoolean());
+ }
+
+ @Test
+ @EnableFlags(FLAG_NOTIFICATIONS_REDESIGN_TEMPLATES)
+ public void testSetSensitiveOnNotifRowUpdatesLayout() throws Exception {
+ // GIVEN a sensitive notification row that's currently redacted
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ measureAndLayout(row);
+ row.setHideSensitiveForIntrinsicHeight(true);
+ row.setSensitive(true, true);
+ assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPublicLayout());
+
+ // GIVEN a mocked private layout
+ NotificationContentView mockPrivateLayout = mock(NotificationContentView.class);
+ row.setPrivateLayout(mockPrivateLayout);
+
+ // WHEN the row is set to no longer be sensitive
+ row.setSensitive(false, true);
+
+ // VERIFY that the layout is updated
+ assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPrivateLayout());
+ verify(mockPrivateLayout).requestSelectLayout(eq(true));
+ }
+
+ @Test
+ @DisableFlags(FLAG_NOTIFICATIONS_REDESIGN_TEMPLATES)
public void testSetSensitiveOnNotifRowNotifiesOfHeightChange() throws Exception {
// GIVEN a sensitive notification row that's currently redacted
ExpandableNotificationRow row = mNotificationTestHelper.createRow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
index 699e8c30afde..47238fedee4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -23,6 +23,7 @@ import android.service.notification.StatusBarNotification
import android.testing.TestableLooper
import android.testing.ViewUtils
import android.view.NotificationHeaderView
+import android.view.NotificationTopLineView
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
@@ -37,6 +38,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.FeedbackIcon
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -82,8 +84,21 @@ class NotificationContentViewTest : SysuiTestCase() {
val mockEntry = createMockNotificationEntry()
row =
spy(
- ExpandableNotificationRow(mContext, /* attrs= */ null, mockEntry).apply {
- entry = mockEntry
+ when (NotificationBundleUi.isEnabled) {
+ true -> {
+ ExpandableNotificationRow(
+ mContext,
+ /* attrs= */ null,
+ UserHandle.CURRENT
+ ).apply {
+ entry = mockEntry
+ }
+ }
+ false -> {
+ ExpandableNotificationRow(mContext, /* attrs= */ null, mockEntry).apply {
+ entry = mockEntry
+ }
+ }
}
)
ViewUtils.attachView(fakeParent)
@@ -270,7 +285,7 @@ class NotificationContentViewTest : SysuiTestCase() {
val icon =
FeedbackIcon(
R.drawable.ic_feedback_alerted,
- R.string.notification_feedback_indicator_alerted
+ R.string.notification_feedback_indicator_alerted,
)
view.setFeedbackIcon(icon)
@@ -291,10 +306,7 @@ class NotificationContentViewTest : SysuiTestCase() {
val mockHeadsUpEB = mock<NotificationExpandButton>()
val mockHeadsUp = createMockNotificationHeaderView(contractedHeight, mockHeadsUpEB)
- val view =
- createContentView(
- isSystemExpanded = false,
- )
+ val view = createContentView(isSystemExpanded = false)
// Update all 3 child forms
view.apply {
@@ -319,12 +331,14 @@ class NotificationContentViewTest : SysuiTestCase() {
private fun createMockNotificationHeaderView(
height: Int,
- mockExpandedEB: NotificationExpandButton
+ mockExpandedEB: NotificationExpandButton,
) =
spy(NotificationHeaderView(mContext, /* attrs= */ null).apply { minimumHeight = height })
.apply {
whenever(this.animate()).thenReturn(mock())
whenever(this.findViewById<View>(R.id.expand_button)).thenReturn(mockExpandedEB)
+ whenever(this.findViewById<View>(R.id.notification_top_line))
+ .thenReturn(mock<NotificationTopLineView>())
}
@Test
@@ -344,7 +358,7 @@ class NotificationContentViewTest : SysuiTestCase() {
isSystemExpanded = false,
contractedView = mockContracted,
expandedView = mockExpanded,
- headsUpView = mockHeadsUp
+ headsUpView = mockHeadsUp,
)
view.setRemoteInputVisible(true)
@@ -373,7 +387,7 @@ class NotificationContentViewTest : SysuiTestCase() {
isSystemExpanded = false,
contractedView = mockContracted,
expandedView = mockExpanded,
- headsUpView = mockHeadsUp
+ headsUpView = mockHeadsUp,
)
view.setRemoteInputVisible(false)
@@ -635,7 +649,7 @@ class NotificationContentViewTest : SysuiTestCase() {
contractedView: View = createViewWithHeight(contractedHeight),
expandedView: View = createViewWithHeight(expandedHeight),
headsUpView: View = createViewWithHeight(contractedHeight),
- row: ExpandableNotificationRow = this.row
+ row: ExpandableNotificationRow = this.row,
): NotificationContentView {
val height = if (isSystemExpanded) expandedHeight else contractedHeight
doReturn(height).whenever(row).intrinsicHeight
@@ -647,7 +661,7 @@ class NotificationContentViewTest : SysuiTestCase() {
setHeights(
/* smallHeight= */ contractedHeight,
/* headsUpMaxHeight= */ contractedHeight,
- /* maxHeight= */ expandedHeight
+ /* maxHeight= */ expandedHeight,
)
contractedChild = contractedView
expandedChild = expandedView
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
index 1b447525bbf5..3d4c90140adb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
@@ -67,6 +67,8 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.icon.appIconProvider
+import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.notificationLockscreenUserManager
import com.android.systemui.statusbar.policy.deviceProvisionedController
@@ -128,6 +130,8 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
private val statusBarStateController = kosmos.statusBarStateController
private val headsUpManager = kosmos.mockHeadsUpManager
private val activityStarter = kosmos.activityStarter
+ private val appIconProvider = kosmos.appIconProvider
+ private val iconStyleProvider = kosmos.notificationIconStyleProvider
private val userManager = kosmos.userManager
private val activeNotificationsInteractor = kosmos.activeNotificationsInteractor
private val sceneInteractor = kosmos.sceneInteractor
@@ -174,6 +178,8 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
accessibilityManager,
highPriorityProvider,
notificationManager,
+ appIconProvider,
+ iconStyleProvider,
userManager,
peopleSpaceWidgetManager,
launcherApps,
@@ -429,6 +435,8 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
.bindNotification(
any<PackageManager>(),
any<INotificationManager>(),
+ eq(appIconProvider),
+ eq(iconStyleProvider),
eq(onUserInteractionCallback),
eq(channelEditorDialogController),
eq(statusBarNotification.packageName),
@@ -463,6 +471,8 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
.bindNotification(
any<PackageManager>(),
any<INotificationManager>(),
+ eq(appIconProvider),
+ eq(iconStyleProvider),
eq(onUserInteractionCallback),
eq(channelEditorDialogController),
eq(statusBarNotification.packageName),
@@ -497,6 +507,8 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
.bindNotification(
any<PackageManager>(),
any<INotificationManager>(),
+ eq(appIconProvider),
+ eq(iconStyleProvider),
eq(onUserInteractionCallback),
eq(channelEditorDialogController),
eq(statusBarNotification.packageName),
@@ -529,8 +541,8 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
.setChannel(testNotificationChannel)
.build()
row
- } catch (e: Exception) {
- org.junit.Assert.fail()
+ } catch (_: Exception) {
+ Assert.fail()
null
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt
index 86689cb88569..86689cb88569 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
index 31f8590c0378..31f8590c0378 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 9137215f8c61..10886760b521 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -343,7 +343,8 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
-@DisableSceneContainer void transitionToShadeLocked() {
+ @DisableSceneContainer
+ public void transitionToShadeLocked() {
mScrimController.legacyTransitionTo(SHADE_LOCKED);
mScrimController.setQsPosition(1f, 0);
finishAnimationsImmediately();
@@ -2028,9 +2029,9 @@ public class ScrimControllerTest extends SysuiTestCase {
// Check combined scrim visibility.
final int visibility;
- if (scrimToAlpha.values().contains(OPAQUE)) {
+ if (scrimToAlpha.containsValue(OPAQUE)) {
visibility = OPAQUE;
- } else if (scrimToAlpha.values().contains(SEMI_TRANSPARENT)) {
+ } else if (scrimToAlpha.containsValue(SEMI_TRANSPARENT)) {
visibility = SEMI_TRANSPARENT;
} else {
visibility = TRANSPARENT;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 6f785a3731e1..dde6e2ee1866 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -65,11 +65,9 @@ import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardMessageAreaController;
import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
@@ -146,7 +144,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock private SysuiStatusBarStateController mStatusBarStateController;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private View mNotificationContainer;
- @Mock private KeyguardBypassController mBypassController;
@Mock private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
@Mock private KeyguardMessageAreaController mKeyguardMessageAreaController;
@Mock private KeyguardMessageArea mKeyguardMessageArea;
@@ -158,7 +155,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock private PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
@Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
- @Mock private UdfpsOverlayInteractor mUdfpsOverlayInteractor;
@Mock private ActivityStarter mActivityStarter;
@Mock private BouncerView mBouncerView;
@Mock private BouncerViewDelegate mBouncerViewDelegate;
@@ -167,7 +163,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock private NotificationShadeWindowView mNotificationShadeWindowView;
@Mock private WindowInsetsController mWindowInsetsController;
@Mock private TaskbarDelegate mTaskbarDelegate;
- @Mock private StatusBarKeyguardViewManager.KeyguardViewManagerCallback mCallback;
@Mock private SelectedUserInteractor mSelectedUserInteractor;
@Mock private DeviceEntryInteractor mDeviceEntryInteractor;
@Mock private SceneInteractor mSceneInteractor;
@@ -190,8 +185,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Captor
private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor;
- @Captor
- private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
@Mock
private KeyguardDismissActionInteractor mKeyguardDismissActionInteractor;
@@ -227,7 +220,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mock(DockManager.class),
mNotificationShadeWindowController,
mKeyguardStateController,
- mKeyguardMessageAreaFactory,
Optional.of(mSysUiUnfoldComponent),
() -> mShadeController,
mLatencyTracker,
@@ -236,7 +228,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mPrimaryBouncerInteractor,
mBouncerView,
mAlternateBouncerInteractor,
- mUdfpsOverlayInteractor,
mActivityStarter,
mKeyguardTransitionInteractor,
mock(KeyguardDismissTransitionInteractor.class),
@@ -732,7 +723,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mock(DockManager.class),
mock(NotificationShadeWindowController.class),
mKeyguardStateController,
- mKeyguardMessageAreaFactory,
Optional.of(mSysUiUnfoldComponent),
() -> mShadeController,
mLatencyTracker,
@@ -741,7 +731,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mPrimaryBouncerInteractor,
mBouncerView,
mAlternateBouncerInteractor,
- mUdfpsOverlayInteractor,
mActivityStarter,
mock(KeyguardTransitionInteractor.class),
mock(KeyguardDismissTransitionInteractor.class),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
index a230f0630d6e..a230f0630d6e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index 1135a5f86952..1135a5f86952 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
index a1122c3cbcd2..a1122c3cbcd2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
index c7b685fba455..c7b685fba455 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
index b93c161a7039..b93c161a7039 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
index 32c598612aa6..32c598612aa6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/CreateUserActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt
index 25ceea951d3c..25ceea951d3c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/CreateUserActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
index 9440280649dd..9440280649dd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
index b3f2113f86ec..b3f2113f86ec 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
index c896fc0bfb8a..c896fc0bfb8a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 8d05ea16cfa6..44392420da49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -465,9 +465,9 @@ public class VolumeDialogImplTest extends SysuiTestCase {
public void notificationVolumeSeparated_theRingerIconChangesToSpeakerIcon() {
// already separated. assert icon is new based on res id
assertEquals(mDialog.mVolumeRingerIconDrawableId,
- R.drawable.ic_speaker_on);
+ R.drawable.ic_legacy_speaker_on);
assertEquals(mDialog.mVolumeRingerMuteIconDrawableId,
- R.drawable.ic_speaker_mute);
+ R.drawable.ic_legacy_speaker_mute);
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt
index b4fbaad6ab37..b4fbaad6ab37 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt
diff --git a/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt
index f893aba240fc..d6e6ea8f9a29 100644
--- a/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt
@@ -20,6 +20,6 @@ import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
-val Kosmos.wallpaperManager: WallpaperManager by Fixture {
+var Kosmos.wallpaperManager: WallpaperManager by Fixture {
WallpaperManager.getInstance(applicationContext)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryKosmos.kt
index a6e71333c816..5dc28bea9bc4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/activity/data/repository/ActivityManagerRepositoryKosmos.kt
@@ -17,33 +17,77 @@
package com.android.systemui.activity.data.repository
import android.app.activityManager
+import com.android.systemui.activity.data.model.AppVisibilityModel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.log.core.Logger
+import com.android.systemui.util.time.SystemClock
+import com.android.systemui.util.time.fakeSystemClock
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-val Kosmos.activityManagerRepository by Kosmos.Fixture { FakeActivityManagerRepository() }
+val Kosmos.activityManagerRepository by
+ Kosmos.Fixture { FakeActivityManagerRepository(fakeSystemClock) }
val Kosmos.realActivityManagerRepository by
- Kosmos.Fixture { ActivityManagerRepositoryImpl(testDispatcher, activityManager) }
+ Kosmos.Fixture {
+ ActivityManagerRepositoryImpl(testDispatcher, fakeSystemClock, activityManager)
+ }
-class FakeActivityManagerRepository : ActivityManagerRepository {
- private val uidFlows = mutableMapOf<Int, MutableList<MutableStateFlow<Boolean>>>()
+class FakeActivityManagerRepository(private val systemClock: SystemClock) :
+ ActivityManagerRepository {
+ private val isVisibleFlows = mutableMapOf<Int, MutableList<MutableStateFlow<Boolean>>>()
+ private val appVisibilityFlows =
+ mutableMapOf<Int, MutableList<MutableStateFlow<AppVisibilityModel>>>()
var startingIsAppVisibleValue = false
+ override fun createAppVisibilityFlow(
+ creationUid: Int,
+ logger: Logger,
+ identifyingLogTag: String,
+ ): Flow<AppVisibilityModel> {
+ val newFlow =
+ MutableStateFlow(
+ if (startingIsAppVisibleValue) {
+ AppVisibilityModel(
+ isAppCurrentlyVisible = true,
+ lastAppVisibleTime = systemClock.currentTimeMillis(),
+ )
+ } else {
+ AppVisibilityModel(isAppCurrentlyVisible = false, lastAppVisibleTime = null)
+ }
+ )
+ appVisibilityFlows.computeIfAbsent(creationUid) { mutableListOf() }.add(newFlow)
+ return newFlow
+ }
+
override fun createIsAppVisibleFlow(
creationUid: Int,
logger: Logger,
identifyingLogTag: String,
): MutableStateFlow<Boolean> {
val newFlow = MutableStateFlow(startingIsAppVisibleValue)
- uidFlows.computeIfAbsent(creationUid) { mutableListOf() }.add(newFlow)
+ isVisibleFlows.computeIfAbsent(creationUid) { mutableListOf() }.add(newFlow)
return newFlow
}
fun setIsAppVisible(uid: Int, isAppVisible: Boolean) {
- uidFlows[uid]?.forEach { stateFlow -> stateFlow.value = isAppVisible }
+ isVisibleFlows[uid]?.forEach { stateFlow -> stateFlow.value = isAppVisible }
+ appVisibilityFlows[uid]?.forEach { stateFlow ->
+ stateFlow.value =
+ if (isAppVisible) {
+ AppVisibilityModel(
+ isAppCurrentlyVisible = true,
+ lastAppVisibleTime = systemClock.currentTimeMillis(),
+ )
+ } else {
+ AppVisibilityModel(
+ isAppCurrentlyVisible = false,
+ stateFlow.value.lastAppVisibleTime,
+ )
+ }
+ }
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorKosmos.kt
index e6e59e1a523e..75c4b6f5366b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractorKosmos.kt
@@ -22,6 +22,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.power.domain.interactor.powerInteractor
val Kosmos.communalSceneTransitionInteractor: CommunalSceneTransitionInteractor by
Kosmos.Fixture {
@@ -33,5 +34,6 @@ val Kosmos.communalSceneTransitionInteractor: CommunalSceneTransitionInteractor
sceneInteractor = communalSceneInteractor,
repository = communalSceneTransitionRepository,
keyguardInteractor = keyguardInteractor,
+ powerInteractor = powerInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt
index 7b0d208298d0..38372acff113 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt
@@ -18,6 +18,8 @@ package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
+import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -39,5 +41,7 @@ val Kosmos.fromAlternateBouncerTransitionInteractor by
powerInteractor = powerInteractor,
keyguardOcclusionInteractor = keyguardOcclusionInteractor,
primaryBouncerInteractor = primaryBouncerInteractor,
+ communalSceneInteractor = communalSceneInteractor,
+ communalSettingsInteractor = communalSettingsInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
index 3c369d7d954f..6b240b5f36ac 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
@@ -18,6 +18,7 @@ package com.android.systemui.keyguard.domain.interactor
import com.android.keyguard.keyguardSecurityModel
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
+import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -37,6 +38,7 @@ var Kosmos.fromPrimaryBouncerTransitionInteractor by
mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
communalSceneInteractor = communalSceneInteractor,
+ communalSettingsInteractor = communalSettingsInteractor,
keyguardSecurityModel = keyguardSecurityModel,
selectedUserInteractor = selectedUserInteractor,
powerInteractor = powerInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
index 8844eb040f02..b781f61723f2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
@@ -20,8 +20,9 @@ import com.android.systemui.keyguard.data.repository.keyguardClockRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
-import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.shade.domain.interactor.shadeModeInteractor
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.promoted.domain.interactor.aodPromotedNotificationInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
import com.android.systemui.wallpapers.domain.interactor.wallpaperFocalAreaInteractor
@@ -30,7 +31,8 @@ val Kosmos.keyguardClockInteractor by
KeyguardClockInteractor(
mediaCarouselInteractor = mediaCarouselInteractor,
activeNotificationsInteractor = activeNotificationsInteractor,
- shadeInteractor = shadeInteractor,
+ aodPromotedNotificationInteractor = aodPromotedNotificationInteractor,
+ shadeModeInteractor = shadeModeInteractor,
keyguardInteractor = keyguardInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
headsUpNotificationInteractor = headsUpNotificationInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
index c0b39b1df7d5..5dc19a340dd0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
@@ -22,7 +22,7 @@ import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
-import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.shade.domain.interactor.shadeModeInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.ui.systemBarUtilsProxy
@@ -33,7 +33,7 @@ val Kosmos.keyguardClockViewModel by
keyguardClockInteractor = keyguardClockInteractor,
applicationScope = applicationCoroutineScope,
aodNotificationIconViewModel = notificationIconContainerAlwaysOnDisplayViewModel,
- shadeInteractor = shadeInteractor,
+ shadeModeInteractor = shadeModeInteractor,
systemBarUtils = systemBarUtilsProxy,
configurationInteractor = configurationInteractor,
resources = mainResources,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelFactoryKosmos.kt
index 16d3fdc26613..345d69aa8df0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelFactoryKosmos.kt
@@ -19,12 +19,17 @@ package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
+import com.android.systemui.shade.domain.interactor.shadeModeInteractor
val Kosmos.keyguardMediaViewModelFactory by
Kosmos.Fixture {
object : KeyguardMediaViewModel.Factory {
override fun create(): KeyguardMediaViewModel {
- return KeyguardMediaViewModel(mediaCarouselInteractor, keyguardInteractor)
+ return KeyguardMediaViewModel(
+ mediaCarouselInteractor = mediaCarouselInteractor,
+ keyguardInteractor = keyguardInteractor,
+ shadeModeInteractor = shadeModeInteractor,
+ )
}
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index ea3feeaf0854..78356318cbb4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.dump.dumpManager
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.pulseExpansionInteractor
@@ -26,6 +27,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.ui.viewmodel.notificationShadeWindowModel
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificationIconContainerAlwaysOnDisplayViewModel
+import com.android.systemui.statusbar.notification.promoted.domain.interactor.aodPromotedNotificationInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.phone.dozeParameters
import com.android.systemui.statusbar.phone.screenOffAnimationController
@@ -41,6 +43,7 @@ val Kosmos.keyguardRootViewModel by Fixture {
keyguardTransitionInteractor = keyguardTransitionInteractor,
notificationsKeyguardInteractor = notificationsKeyguardInteractor,
pulseExpansionInteractor = pulseExpansionInteractor,
+ aodPromotedNotificationInteractor = aodPromotedNotificationInteractor,
aodNotificationIconViewModel = notificationIconContainerAlwaysOnDisplayViewModel,
notificationShadeWindowModel = notificationShadeWindowModel,
alternateBouncerToAodTransitionViewModel = alternateBouncerToAodTransitionViewModel,
@@ -90,5 +93,6 @@ val Kosmos.keyguardRootViewModel by Fixture {
aodBurnInViewModel = aodBurnInViewModel,
shadeInteractor = shadeInteractor,
wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor,
+ dumpManager = dumpManager,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
index dd13b8b143ae..b751e213152e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
@@ -25,7 +25,7 @@ import com.android.systemui.keyguard.shared.transition.KeyguardTransitionAnimati
import com.android.systemui.keyguard.shared.transition.keyguardTransitionAnimationCallbackDelegator
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.shade.domain.interactor.shadeModeInteractor
import com.android.systemui.unfold.domain.interactor.unfoldTransitionInteractor
val Kosmos.lockscreenContentViewModelFactory by Fixture {
@@ -38,7 +38,7 @@ val Kosmos.lockscreenContentViewModelFactory by Fixture {
interactor = keyguardBlueprintInteractor,
authController = authController,
touchHandling = keyguardTouchHandlingViewModel,
- shadeInteractor = shadeInteractor,
+ shadeModeInteractor = shadeModeInteractor,
unfoldTransitionInteractor = unfoldTransitionInteractor,
deviceEntryInteractor = deviceEntryInteractor,
transitionInteractor = keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt
index 60c0f342b874..f9917ac680e0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt
@@ -44,6 +44,8 @@ class FakeSceneDataSource(initialSceneKey: SceneKey, val testScope: TestScope) :
var pendingOverlays: Set<OverlayKey>? = null
private set
+ var freezeAndAnimateToCurrentStateCallCount = 0
+
override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) {
if (_isPaused) {
_pendingScene = toScene
@@ -85,6 +87,10 @@ class FakeSceneDataSource(initialSceneKey: SceneKey, val testScope: TestScope) :
hideOverlay(overlay)
}
+ override fun freezeAndAnimateToCurrentState() {
+ freezeAndAnimateToCurrentStateCallCount++
+ }
+
/**
* Pauses scene and overlay changes.
*
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerKosmos.kt
index 67dd0ad896d5..0892e66b8b86 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTrackerKosmos.kt
@@ -27,7 +27,7 @@ import java.util.Optional
val Kosmos.shadeDisplayChangeLatencyTracker by Fixture {
ShadeDisplayChangeLatencyTracker(
- Optional.of(mockShadeRootView),
+ mockShadeRootView,
configurationRepository,
latencyTracker,
testScope.backgroundScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt
index 46314135c574..1397d974cbc5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt
@@ -29,7 +29,6 @@ import com.android.systemui.statusbar.notification.domain.interactor.activeNotif
import com.android.systemui.statusbar.notification.row.notificationRebindingTracker
import com.android.systemui.statusbar.notification.stack.notificationStackRebindingHider
import com.android.systemui.statusbar.policy.configurationController
-import java.util.Optional
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@@ -55,11 +54,11 @@ val Kosmos.shadeDisplaysInteractor by
testScope.backgroundScope,
testScope.backgroundScope.coroutineContext,
mockedShadeDisplayChangeLatencyTracker,
- Optional.of(shadeExpandedStateInteractor),
+ shadeExpandedStateInteractor,
shadeExpansionIntent,
activeNotificationsInteractor,
notificationRebindingTracker,
- Optional.of(notificationStackRebindingHider),
+ notificationStackRebindingHider,
configurationController,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt
index 20e4523fda0f..55e35f2b2703 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt
@@ -18,9 +18,11 @@ package com.android.systemui.shade.ui.viewmodel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModelFactory
@@ -31,6 +33,8 @@ val Kosmos.notificationsShadeOverlayContentViewModel:
notificationsPlaceholderViewModelFactory = notificationsPlaceholderViewModelFactory,
sceneInteractor = sceneInteractor,
shadeInteractor = shadeInteractor,
+ disableFlagsInteractor = disableFlagsInteractor,
+ mediaCarouselInteractor = mediaCarouselInteractor,
activeNotificationsInteractor = activeNotificationsInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt
index 878c2deb43b2..d8e0cfe4fbf8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt
@@ -21,6 +21,7 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
+import com.android.systemui.util.time.fakeSystemClock
val Kosmos.notifChipsViewModel: NotifChipsViewModel by
Kosmos.Fixture {
@@ -29,5 +30,6 @@ val Kosmos.notifChipsViewModel: NotifChipsViewModel by
applicationCoroutineScope,
statusBarNotificationChipsInteractor,
headsUpNotificationInteractor,
+ fakeSystemClock,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt
index 93502f365202..b876095fefe5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt
@@ -17,13 +17,14 @@
package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.mediaControlChipViewModel
-val Kosmos.statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel by
+private val Kosmos.statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel by
+ Kosmos.Fixture { StatusBarPopupChipsViewModel(mediaControlChip = mediaControlChipViewModel) }
+
+val Kosmos.statusBarPopupChipsViewModelFactory by
Kosmos.Fixture {
- StatusBarPopupChipsViewModel(
- testScope.backgroundScope,
- mediaControlChipViewModel = mediaControlChipViewModel,
- )
+ object : StatusBarPopupChipsViewModel.Factory {
+ override fun create(): StatusBarPopupChipsViewModel = statusBarPopupChipsViewModel
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationEntryBuilderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationEntryBuilderKosmos.kt
new file mode 100644
index 000000000000..59f5ecd2563f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationEntryBuilderKosmos.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.app.Person
+import android.content.Intent
+import android.content.applicationContext
+import android.graphics.drawable.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.icon.IconPack
+import com.android.systemui.statusbar.notification.promoted.setPromotedContent
+import org.mockito.kotlin.mock
+
+fun Kosmos.setIconPackWithMockIconViews(entry: NotificationEntry) {
+ entry.icons =
+ IconPack.buildPack(
+ /* statusBarIcon = */ mock(),
+ /* statusBarChipIcon = */ mock(),
+ /* shelfIcon = */ mock(),
+ /* aodIcon = */ mock(),
+ /* source = */ null,
+ )
+}
+
+fun Kosmos.buildOngoingCallEntry(
+ promoted: Boolean = false,
+ block: NotificationEntryBuilder.() -> Unit = {},
+): NotificationEntry =
+ buildNotificationEntry(
+ tag = "call",
+ promoted = promoted,
+ style = makeOngoingCallStyle(),
+ block = block,
+ )
+
+fun Kosmos.buildPromotedOngoingEntry(
+ block: NotificationEntryBuilder.() -> Unit = {}
+): NotificationEntry =
+ buildNotificationEntry(tag = "ron", promoted = true, style = null, block = block)
+
+fun Kosmos.buildNotificationEntry(
+ tag: String? = null,
+ promoted: Boolean = false,
+ style: Notification.Style? = null,
+ block: NotificationEntryBuilder.() -> Unit = {},
+): NotificationEntry =
+ NotificationEntryBuilder()
+ .apply {
+ setTag(tag)
+ setFlag(applicationContext, Notification.FLAG_PROMOTED_ONGOING, promoted)
+ modifyNotification(applicationContext)
+ .setSmallIcon(Icon.createWithContentUri("content://null"))
+ .setStyle(style)
+ }
+ .apply(block)
+ .build()
+ .also {
+ setIconPackWithMockIconViews(it)
+ if (promoted) setPromotedContent(it)
+ }
+
+private fun Kosmos.makeOngoingCallStyle(): Notification.CallStyle {
+ val pendingIntent =
+ PendingIntent.getBroadcast(
+ applicationContext,
+ 0,
+ Intent("action"),
+ PendingIntent.FLAG_IMMUTABLE,
+ )
+ val person = Person.Builder().setName("person").build()
+ return Notification.CallStyle.forOngoingCall(person, pendingIntent)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
index 8b4de2bcc26f..05f1c0bac982 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
@@ -33,3 +33,6 @@ inline fun NotificationEntry.modifyEntry(
fun getAttachState(entry: ListEntry): ListAttachState {
return entry.attachState
}
+
+fun buildEntry(block: NotificationEntryBuilder.() -> Unit) =
+ NotificationEntryBuilder().apply(block).build()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotifPipelineKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotifPipelineKosmos.kt
index a48b27015c02..fa3702cea5ee 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotifPipelineKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotifPipelineKosmos.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.util.mockito.mock
+import org.mockito.kotlin.mock
-var Kosmos.notifPipeline by Kosmos.Fixture { mock<NotifPipeline>() }
+var Kosmos.notifPipeline by Kosmos.Fixture { mockNotifPipeline }
+var Kosmos.mockNotifPipeline by Kosmos.Fixture { mock<NotifPipeline>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt
index dc7595f7f2e4..87e0a0f0dda3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt
@@ -24,6 +24,7 @@ import com.android.systemui.statusbar.data.repository.notificationListenerSettin
import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor
+import com.android.systemui.statusbar.notification.promoted.domain.interactor.aodPromotedNotificationInteractor
import com.android.wm.shell.bubbles.bubblesOptional
val Kosmos.alwaysOnDisplayNotificationIconsInteractor by Fixture {
@@ -47,6 +48,7 @@ val Kosmos.notificationIconsInteractor by Fixture {
activeNotificationsInteractor = activeNotificationsInteractor,
bubbles = bubblesOptional,
headsUpNotificationIconInteractor = headsUpNotificationIconInteractor,
+ aodPromotedNotificationInteractor = aodPromotedNotificationInteractor,
keyguardViewStateRepository = notificationsKeyguardViewStateRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
index 63521de096c9..e55cd0dc16f4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
@@ -16,8 +16,11 @@
package com.android.systemui.statusbar.notification.promoted
+import android.app.Notification
import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.row.RowImageInflater
import com.android.systemui.statusbar.notification.row.shared.skeletonImageTransform
var Kosmos.promotedNotificationContentExtractor by
@@ -28,3 +31,14 @@ var Kosmos.promotedNotificationContentExtractor by
promotedNotificationLogger,
)
}
+
+fun Kosmos.setPromotedContent(entry: NotificationEntry) {
+ val extractedContent =
+ promotedNotificationContentExtractor.extractContent(
+ entry,
+ Notification.Builder.recoverBuilder(applicationContext, entry.sbn.notification),
+ RowImageInflater.newInstance(null).useForContentModel(),
+ )
+ entry.promotedNotificationContentModel =
+ requireNotNull(extractedContent) { "extractContent returned null" }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt
index 57c8fd066ea8..fcd484353011 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.communal.domain.interactor
+package com.android.systemui.statusbar.notification.promoted.domain.interactor
+import com.android.systemui.dump.dumpManager
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.scene.domain.interactor.sceneInteractor
-val Kosmos.communalBackActionInteractor by
+val Kosmos.aodPromotedNotificationInteractor by
Kosmos.Fixture {
- CommunalBackActionInteractor(
- communalInteractor = communalInteractor,
- communalSceneInteractor = communalSceneInteractor,
- sceneInteractor = sceneInteractor,
+ AODPromotedNotificationInteractor(
+ promotedNotificationsInteractor = promotedNotificationsInteractor,
+ dumpManager = dumpManager,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorKosmos.kt
new file mode 100644
index 000000000000..093ec10e2642
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorKosmos.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.promoted.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.statusbar.chips.call.domain.interactor.callChipInteractor
+import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+
+val Kosmos.promotedNotificationsInteractor by
+ Kosmos.Fixture {
+ PromotedNotificationsInteractor(
+ activeNotificationsInteractor = activeNotificationsInteractor,
+ callChipInteractor = callChipInteractor,
+ notifChipsInteractor = statusBarNotificationChipsInteractor,
+ backgroundDispatcher = testDispatcher,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index e445a73b06d0..8b19491bfdf8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -41,6 +41,7 @@ import com.android.systemui.media.controls.util.MediaFeatureFlag
import com.android.systemui.media.dialog.MediaOutputDialogManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.shared.system.DevicePolicyManagerWrapper
import com.android.systemui.shared.system.PackageManagerWrapper
@@ -346,10 +347,15 @@ class ExpandableNotificationRowBuilder(
// NOTE: This flag is read when the ExpandableNotificationRow is inflated, so it needs to be
// set, but we do not want to override an existing value that is needed by a specific test.
+ val userTracker = Mockito.mock(UserTracker::class.java, STUB_ONLY)
+ whenever(userTracker.userHandle).thenReturn(context.user)
+
val rowInflaterTask =
RowInflaterTask(
mFakeSystemClock,
Mockito.mock(RowInflaterTaskLogger::class.java, STUB_ONLY),
+ userTracker,
+ Mockito.mock(AsyncRowInflater::class.java, STUB_ONLY),
)
val row = rowInflaterTask.inflateSynchronously(context, null, entry)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt
index bc1363ac3d5c..970b87cd368a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt
@@ -33,7 +33,7 @@ import java.util.Optional
val Kosmos.notificationListViewBinder by Fixture {
NotificationListViewBinder(
- backgroundDispatcher = testDispatcher,
+ inflationDispatcher = testDispatcher,
hiderTracker = displaySwitchNotificationsHiderTracker,
configuration = configurationState,
falsingManager = falsingManager,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index 352f6cf011e1..9b6f205fba72 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -26,6 +26,7 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
class FakeMobileIconsInteractor(
mobileMappings: MobileMappingsProxy,
@@ -73,6 +74,8 @@ class FakeMobileIconsInteractor(
override val icons: MutableStateFlow<List<MobileIconInteractor>> = MutableStateFlow(emptyList())
+ override val isStackable: StateFlow<Boolean> = MutableStateFlow(false)
+
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
index fbada934c9d4..a97c651ba426 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
@@ -29,7 +29,7 @@ import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel
import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
import com.android.systemui.statusbar.events.domain.interactor.systemStatusEventAnimationInteractor
-import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModel
+import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModelFactory
import com.android.systemui.statusbar.layout.ui.viewmodel.multiDisplayStatusBarContentInsetsViewModelStore
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
@@ -59,7 +59,7 @@ var Kosmos.homeStatusBarViewModel: HomeStatusBarViewModel by
shadeInteractor,
shareToAppChipViewModel,
ongoingActivityChipsViewModel,
- statusBarPopupChipsViewModel,
+ statusBarPopupChipsViewModelFactory,
systemStatusEventAnimationInteractor,
multiDisplayStatusBarContentInsetsViewModelStore,
backgroundScope,
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/colors/ShadeColors.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/data/repository/SecureSettingsForUserRepositoryKosmos.kt
index 70ace6a6d038..81f71e9f7b2f 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/colors/ShadeColors.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/data/repository/SecureSettingsForUserRepositoryKosmos.kt
@@ -14,19 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.common.shared.colors
+package com.android.systemui.util.settings.data.repository
-import android.content.res.Resources
-import android.graphics.Color
-import com.android.internal.graphics.ColorUtils
-import com.android.systemui.res.R
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.backgroundCoroutineContext
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.util.settings.fakeSettings
+import com.android.systemui.util.settings.repository.SecureSettingsForUserRepository
-object ShadeColors {
- @JvmStatic
- fun Resources.shadeBasePanel(): Int {
- val layerAbove =
- ColorUtils.setAlphaComponent(getColor(R.color.shade_panel), (0.4f * 255).toInt())
- val layerBelow = ColorUtils.setAlphaComponent(Color.WHITE, (0.1f * 255).toInt())
- return ColorUtils.compositeColors(layerAbove, layerBelow)
+val Kosmos.secureSettingsForUserRepository by
+ Kosmos.Fixture {
+ SecureSettingsForUserRepository(fakeSettings, testDispatcher, backgroundCoroutineContext)
}
-}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt
index 703d6ad83eac..a209ec9d0c9c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt
@@ -31,3 +31,6 @@ val Kosmos.systemClock by
}
val Kosmos.fakeSystemClock by Kosmos.Fixture { FakeSystemClock() }
+
+val SystemClock.fake
+ get() = this as FakeSystemClock
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinderKosmos.kt
index dc09e3233b1e..386e0feb3b3a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinderKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinderKosmos.kt
@@ -16,7 +16,6 @@
package com.android.systemui.volume.dialog.ui.binder
-import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.volume.dialog.ringer.volumeDialogRingerViewBinder
import com.android.systemui.volume.dialog.settings.ui.binder.volumeDialogSettingsButtonViewBinder
@@ -28,12 +27,13 @@ import com.android.systemui.volume.dialog.utils.volumeTracer
val Kosmos.volumeDialogViewBinder by
Kosmos.Fixture {
VolumeDialogViewBinder(
- applicationContext.resources,
volumeDialogViewModel,
jankListenerFactory,
volumeTracer,
- volumeDialogRingerViewBinder,
- volumeDialogSlidersViewBinder,
- volumeDialogSettingsButtonViewBinder,
+ listOf(
+ volumeDialogSlidersViewBinder,
+ volumeDialogRingerViewBinder,
+ volumeDialogSettingsButtonViewBinder,
+ ),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt
index 96bc9722635a..8c8d0240f572 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioSharingStreamSliderViewModelKosmos.kt
@@ -16,11 +16,11 @@
package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
-import android.content.applicationContext
import com.android.internal.logging.uiEventLogger
import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.volume.domain.interactor.audioSharingInteractor
+import com.android.systemui.volume.shared.volumePanelLogger
import kotlinx.coroutines.CoroutineScope
val Kosmos.audioSharingStreamSliderViewModelFactory by
@@ -29,10 +29,10 @@ val Kosmos.audioSharingStreamSliderViewModelFactory by
override fun create(coroutineScope: CoroutineScope): AudioSharingStreamSliderViewModel {
return AudioSharingStreamSliderViewModel(
coroutineScope,
- applicationContext,
audioSharingInteractor,
uiEventLogger,
sliderHapticsViewModelFactory,
+ volumePanelLogger,
)
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt
index abd4235143f1..6875619d45fc 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt
@@ -21,6 +21,7 @@ import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.volume.mediaDeviceSessionInteractor
import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession
+import com.android.systemui.volume.shared.volumePanelLogger
import kotlinx.coroutines.CoroutineScope
val Kosmos.castVolumeSliderViewModelFactory by
@@ -36,6 +37,7 @@ val Kosmos.castVolumeSliderViewModelFactory by
applicationContext,
mediaDeviceSessionInteractor,
sliderHapticsViewModelFactory,
+ volumePanelLogger,
)
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt
index aeff86ed89bb..24d2f1f0d901 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt
@@ -34,12 +34,15 @@ class FakeWallpaperFocalAreaRepository : WallpaperFocalAreaRepository {
_wallpaperFocalAreaBounds.asStateFlow()
private val _wallpaperFocalAreaTapPosition = MutableStateFlow(PointF(0F, 0F))
- override val wallpaperFocalAreaTapPosition: StateFlow<PointF> =
+ val wallpaperFocalAreaTapPosition: StateFlow<PointF> =
_wallpaperFocalAreaTapPosition.asStateFlow()
private val _notificationDefaultTop = MutableStateFlow(0F)
override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow()
+ private val _hasFocalArea = MutableStateFlow(false)
+ override val hasFocalArea: StateFlow<Boolean> = _hasFocalArea.asStateFlow()
+
override fun setShortcutAbsoluteTop(top: Float) {
_shortcutAbsoluteTop.value = top
}
@@ -56,7 +59,7 @@ class FakeWallpaperFocalAreaRepository : WallpaperFocalAreaRepository {
_wallpaperFocalAreaBounds.value = bounds
}
- override fun setTapPosition(point: PointF) {
- _wallpaperFocalAreaTapPosition.value = point
+ override fun setTapPosition(tapPosition: PointF) {
+ _wallpaperFocalAreaTapPosition.value = tapPosition
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
index 8689e04e62dd..66bb803c182d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
@@ -17,6 +17,8 @@
package com.android.systemui.wallpapers.data.repository
import android.app.WallpaperInfo
+import android.graphics.PointF
+import android.graphics.RectF
import android.view.View
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -34,9 +36,9 @@ class FakeWallpaperRepository : WallpaperRepository {
private val _shouldSendFocalArea = MutableStateFlow(false)
override val shouldSendFocalArea: StateFlow<Boolean> = _shouldSendFocalArea.asStateFlow()
- fun setShouldSendFocalArea(shouldSendFocalArea: Boolean) {
- _shouldSendFocalArea.value = shouldSendFocalArea
- }
+ override fun sendLockScreenLayoutChangeCommand(wallpaperFocalAreaBounds: RectF) {}
+
+ override fun sendTapCommand(tapPosition: PointF) {}
fun setWallpaperInfo(wallpaperInfo: WallpaperInfo?) {
_wallpaperInfo.value = wallpaperInfo
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
index 6b955ffb0b68..1761503b2cc9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
@@ -16,9 +16,24 @@
package com.android.systemui.wallpapers.data.repository
+import android.content.applicationContext
+import com.android.app.wallpaperManager
+import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.user.data.repository.userRepository
+import com.android.systemui.util.settings.fakeSettings
-var Kosmos.fakeWallpaperRepository by Kosmos.Fixture { FakeWallpaperRepository() }
-
-var Kosmos.wallpaperRepository: WallpaperRepository by Kosmos.Fixture { fakeWallpaperRepository }
+val Kosmos.wallpaperRepository by Fixture {
+ WallpaperRepositoryImpl(
+ context = applicationContext,
+ scope = testScope.backgroundScope,
+ bgDispatcher = testDispatcher,
+ broadcastDispatcher = broadcastDispatcher,
+ userRepository = userRepository,
+ wallpaperManager = wallpaperManager,
+ secureSettings = fakeSettings,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
index 88eb5511160b..eaf55a72be93 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt
@@ -18,20 +18,14 @@ package com.android.systemui.wallpapers.domain.interactor
import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.wallpapers.data.repository.wallpaperFocalAreaRepository
-import com.android.systemui.wallpapers.data.repository.wallpaperRepository
-val Kosmos.wallpaperFocalAreaInteractor by
+var Kosmos.wallpaperFocalAreaInteractor by
Kosmos.Fixture {
WallpaperFocalAreaInteractor(
- applicationScope = applicationCoroutineScope,
context = applicationContext,
wallpaperFocalAreaRepository = wallpaperFocalAreaRepository,
shadeRepository = shadeRepository,
- activeNotificationsInteractor = activeNotificationsInteractor,
- wallpaperRepository = wallpaperRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
index 7e232c526732..4032503d04c1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt
@@ -16,10 +16,14 @@
package com.android.systemui.wallpapers.ui.viewmodel
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.wallpapers.domain.interactor.wallpaperFocalAreaInteractor
var Kosmos.wallpaperFocalAreaViewModel by
Kosmos.Fixture {
- WallpaperFocalAreaViewModel(wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor)
+ WallpaperFocalAreaViewModel(
+ wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor,
+ keyguardTransitionInteractor = keyguardTransitionInteractor,
+ )
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepositoryKosmos.kt
index 96992233375d..b619e2d70724 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepositoryKosmos.kt
@@ -29,4 +29,5 @@ class FakeWindowRootViewBlurRepository : WindowRootViewBlurRepository {
override val blurRadius: MutableStateFlow<Int> = MutableStateFlow(0)
override val isBlurOpaque: MutableStateFlow<Boolean> = MutableStateFlow(false)
override val isBlurSupported: MutableStateFlow<Boolean> = MutableStateFlow(false)
+ override var blurAppliedListener: BlurAppliedListener? = null
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java
new file mode 100644
index 000000000000..7ee9d7a8a5c6
--- /dev/null
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.platform.test.ravenwood;
+
+import com.android.ravenwood.RavenwoodRuntimeNative;
+
+import java.io.PrintStream;
+import java.util.HashSet;
+import java.util.Objects;
+
+/**
+ * Provides a method call hook that prints almost all (see below) the framework methods being
+ * called with indentation.
+ *
+ * We don't log methods that are trivial, uninteresting, or would be too noisy.
+ * e.g. we don't want to log any logging related methods, or collection APIs.
+ *
+ */
+public class RavenwoodMethodCallLogger {
+ private RavenwoodMethodCallLogger() {
+ }
+
+ /** We don't want to log anything before ravenwood is initialized. This flag controls it.*/
+ private static volatile boolean sEnabled = false;
+
+ private static volatile PrintStream sOut = System.out;
+
+ /** Return the current thread's call nest level. */
+ private static int getNestLevel() {
+ return Thread.currentThread().getStackTrace().length;
+ }
+
+ private static class ThreadInfo {
+ /**
+ * We save the current thread's nest call level here and use that as the initial level.
+ * We do it because otherwise the nest level would be too deep by the time test
+ * starts.
+ */
+ public final int mInitialNestLevel = getNestLevel();
+
+ /**
+ * A nest level where shouldLog() returned false.
+ * Once it's set, we ignore all calls deeper than this.
+ */
+ public int mDisabledNestLevel = Integer.MAX_VALUE;
+ }
+
+ private static final ThreadLocal<ThreadInfo> sThreadInfo = new ThreadLocal<>() {
+ @Override
+ protected ThreadInfo initialValue() {
+ return new ThreadInfo();
+ }
+ };
+
+ /** Classes that should be logged. Uses a map for fast lookup. */
+ private static final HashSet<Class> sIgnoreClasses = new HashSet<>();
+ static {
+ // The following classes are not interesting...
+ sIgnoreClasses.add(android.util.Log.class);
+ sIgnoreClasses.add(android.util.Slog.class);
+ sIgnoreClasses.add(android.util.EventLog.class);
+ sIgnoreClasses.add(android.util.TimingsTraceLog.class);
+
+ sIgnoreClasses.add(android.util.SparseArray.class);
+ sIgnoreClasses.add(android.util.SparseIntArray.class);
+ sIgnoreClasses.add(android.util.SparseLongArray.class);
+ sIgnoreClasses.add(android.util.SparseBooleanArray.class);
+ sIgnoreClasses.add(android.util.SparseDoubleArray.class);
+ sIgnoreClasses.add(android.util.SparseSetArray.class);
+ sIgnoreClasses.add(android.util.SparseArrayMap.class);
+ sIgnoreClasses.add(android.util.LongSparseArray.class);
+ sIgnoreClasses.add(android.util.LongSparseLongArray.class);
+ sIgnoreClasses.add(android.util.LongArray.class);
+
+ sIgnoreClasses.add(android.text.FontConfig.class);
+
+ sIgnoreClasses.add(android.os.SystemClock.class);
+ sIgnoreClasses.add(android.os.Trace.class);
+ sIgnoreClasses.add(android.os.LocaleList.class);
+ sIgnoreClasses.add(android.os.Build.class);
+ sIgnoreClasses.add(android.os.SystemProperties.class);
+
+ sIgnoreClasses.add(com.android.internal.util.Preconditions.class);
+
+ sIgnoreClasses.add(android.graphics.FontListParser.class);
+ sIgnoreClasses.add(android.graphics.ColorSpace.class);
+
+ sIgnoreClasses.add(android.graphics.fonts.FontStyle.class);
+ sIgnoreClasses.add(android.graphics.fonts.FontVariationAxis.class);
+
+ sIgnoreClasses.add(com.android.internal.compat.CompatibilityChangeInfo.class);
+ sIgnoreClasses.add(com.android.internal.os.LoggingPrintStream.class);
+
+ sIgnoreClasses.add(android.os.ThreadLocalWorkSource.class);
+
+ // Following classes *may* be interesting for some purposes, but the initialization is
+ // too noisy...
+ sIgnoreClasses.add(android.graphics.fonts.SystemFonts.class);
+
+ }
+
+ /**
+ * Return if a class should be ignored. Uses {link #sIgnoreCladsses}, but
+ * we ignore more classes.
+ */
+ private static boolean shouldIgnoreClass(Class<?> clazz) {
+ if (sIgnoreClasses.contains(clazz)) {
+ return true;
+ }
+ // Let's also ignore collection-ish classes in android.util.
+ if (java.util.Collection.class.isAssignableFrom(clazz)
+ || java.util.Map.class.isAssignableFrom(clazz)
+ ) {
+ if ("android.util".equals(clazz.getPackageName())) {
+ return true;
+ }
+ return false;
+ }
+
+ switch (clazz.getSimpleName()) {
+ case "EventLogTags":
+ return false;
+ }
+
+ // Following are classes that can't be referred to here directly.
+ // e.g. AndroidPrintStream is package-private, so we can't use its "class" here.
+ switch (clazz.getName()) {
+ case "com.android.internal.os.AndroidPrintStream":
+ return false;
+ }
+ return false;
+ }
+
+ private static boolean shouldLog(
+ Class<?> methodClass,
+ String methodName,
+ @SuppressWarnings("UnusedVariable") String methodDescriptor
+ ) {
+ // Should we ignore this class?
+ if (shouldIgnoreClass(methodClass)) {
+ return false;
+ }
+ // Is it a nested class in a class that should be ignored?
+ var host = methodClass.getNestHost();
+ if (host != methodClass && shouldIgnoreClass(host)) {
+ return false;
+ }
+
+ var className = methodClass.getName();
+
+ // Ad-hoc ignore list. They'd be too noisy.
+ if ("create".equals(methodName)
+ // We may apply jarjar, so use endsWith().
+ && className.endsWith("com.android.server.compat.CompatConfig")) {
+ return false;
+ }
+
+ var pkg = methodClass.getPackageName();
+ if (pkg.startsWith("android.icu")) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Call this to enable logging.
+ */
+ public static void enable(PrintStream out) {
+ sEnabled = true;
+ sOut = Objects.requireNonNull(out);
+
+ // It's called from the test thread (Java's main thread). Because we're already
+ // in deep nest calls, we initialize the initial nest level here.
+ sThreadInfo.get();
+ }
+
+ /** Actual method hook entry point.*/
+ public static void logMethodCall(
+ Class<?> methodClass,
+ String methodName,
+ String methodDescriptor
+ ) {
+ if (!sEnabled) {
+ return;
+ }
+ final var ti = sThreadInfo.get();
+ final int nestLevel = getNestLevel() - ti.mInitialNestLevel;
+
+ // Once shouldLog() returns false, we just ignore all deeper calls.
+ if (ti.mDisabledNestLevel < nestLevel) {
+ return; // Still ignore.
+ }
+ final boolean shouldLog = shouldLog(methodClass, methodName, methodDescriptor);
+
+ if (!shouldLog) {
+ ti.mDisabledNestLevel = nestLevel;
+ return;
+ }
+ ti.mDisabledNestLevel = Integer.MAX_VALUE;
+
+ var out = sOut;
+ out.print("# [");
+ out.print(RavenwoodRuntimeNative.gettid());
+ out.print(": ");
+ out.print(Thread.currentThread().getName());
+ out.print("]: ");
+ out.print("[@");
+ out.printf("%2d", nestLevel);
+ out.print("] ");
+ for (int i = 0; i < nestLevel; i++) {
+ out.print(" ");
+ }
+ out.println(methodClass.getName() + "." + methodName + methodDescriptor);
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 7af03ed2e6c8..ae88bb234e9d 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -23,7 +23,6 @@ import static android.platform.test.ravenwood.RavenwoodSystemServer.ANDROID_PACK
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_INST_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
-import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP;
import static com.android.ravenwood.common.RavenwoodCommonUtils.parseNullableInt;
import static com.android.ravenwood.common.RavenwoodCommonUtils.withDefault;
@@ -103,6 +102,10 @@ public class RavenwoodRuntimeEnvironmentController {
private RavenwoodRuntimeEnvironmentController() {
}
+ private static final PrintStream sStdOut = System.out;
+ @SuppressWarnings("UnusedVariable")
+ private static final PrintStream sStdErr = System.err;
+
private static final String MAIN_THREAD_NAME = "RavenwoodMain";
private static final String LIBRAVENWOOD_INITIALIZER_NAME = "ravenwood_initializer";
private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime";
@@ -212,9 +215,9 @@ public class RavenwoodRuntimeEnvironmentController {
}
private static void globalInitInner() throws IOException {
- if (RAVENWOOD_VERBOSE_LOGGING) {
- Log.v(TAG, "globalInit() called here...", new RuntimeException("NOT A CRASH"));
- }
+ // We haven't initialized liblog yet, so directly write to System.out here.
+ RavenwoodCommonUtils.log(TAG, "globalInitInner()");
+
if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) {
Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
}
@@ -234,9 +237,6 @@ public class RavenwoodRuntimeEnvironmentController {
dumpJavaProperties();
dumpOtherInfo();
- // We haven't initialized liblog yet, so directly write to System.out here.
- RavenwoodCommonUtils.log(TAG, "globalInitInner()");
-
// Make sure libravenwood_runtime is loaded.
System.load(RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_RUNTIME_NAME));
@@ -261,6 +261,9 @@ public class RavenwoodRuntimeEnvironmentController {
// Make sure libandroid_runtime is loaded.
RavenwoodNativeLoader.loadFrameworkNativeCode();
+ // Start method logging.
+ RavenwoodMethodCallLogger.enable(sStdOut);
+
// Touch some references early to ensure they're <clinit>'ed
Objects.requireNonNull(Build.TYPE);
Objects.requireNonNull(Build.VERSION.SDK);
diff --git a/ravenwood/runtime-jni/ravenwood_initializer.cpp b/ravenwood/runtime-jni/ravenwood_initializer.cpp
index 391c5d56b212..8a35ade649b2 100644
--- a/ravenwood/runtime-jni/ravenwood_initializer.cpp
+++ b/ravenwood/runtime-jni/ravenwood_initializer.cpp
@@ -26,6 +26,10 @@
#include <fcntl.h>
#include <set>
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <cstdlib>
#include "jni_helper.h"
@@ -182,17 +186,82 @@ static jboolean removeSystemProperty(JNIEnv* env, jclass, jstring javaKey) {
}
}
+// Find the PPID of child_pid using /proc/N/stat. The 4th field is the PPID.
+// Also returns child_pid's process name (2nd field).
+static pid_t getppid_of(pid_t child_pid, std::string& out_process_name) {
+ if (child_pid < 0) {
+ return -1;
+ }
+ std::string stat_file = "/proc/" + std::to_string(child_pid) + "/stat";
+ std::ifstream stat_stream(stat_file);
+ if (!stat_stream.is_open()) {
+ ALOGW("Unable to open '%s': %s", stat_file.c_str(), strerror(errno));
+ return -1;
+ }
+
+ std::string field;
+ int field_count = 0;
+ while (std::getline(stat_stream, field, ' ')) {
+ if (++field_count == 4) {
+ return atoi(field.c_str());
+ }
+ if (field_count == 2) {
+ out_process_name = field;
+ }
+ }
+ ALOGW("Unexpected format in '%s'", stat_file.c_str());
+ return -1;
+}
+
+// Find atest's PID. Climb up the process tree, and find "atest-py3".
+static pid_t find_atest_pid() {
+ auto ret = getpid(); // self (isolation runner process)
+
+ while (ret != -1) {
+ std::string proc;
+ ret = getppid_of(ret, proc);
+ if (proc == "(atest-py3)") {
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+// If $RAVENWOOD_LOG_OUT is set, redirect stdout/err to this file.
+// Originally it was added to allow to monitor log in realtime, with
+// RAVENWOOD_LOG_OUT=$(tty) atest...
+//
+// As a special case, if $RAVENWOOD_LOG_OUT is set to "-", we try to find
+// atest's process and send the output to its stdout. It's sort of hacky, but
+// this allows shell redirection to work on Ravenwood output too,
+// so e.g. `atest ... |tee atest.log` would work on Ravenwood's output.
+// (which wouldn't work with `RAVENWOOD_LOG_OUT=$(tty)`).
+//
+// Otherwise -- if $RAVENWOOD_LOG_OUT isn't set -- atest/tradefed just writes
+// the test's output to its own log file.
static void maybeRedirectLog() {
auto ravenwoodLogOut = getenv("RAVENWOOD_LOG_OUT");
- if (ravenwoodLogOut == NULL) {
+ if (ravenwoodLogOut == NULL || *ravenwoodLogOut == '\0') {
return;
}
- ALOGI("RAVENWOOD_LOG_OUT set. Redirecting output to %s", ravenwoodLogOut);
+ std::string path;
+ if (strcmp("-", ravenwoodLogOut) == 0) {
+ pid_t ppid = find_atest_pid();
+ if (ppid < 0) {
+ ALOGI("RAVENWOOD_LOG_OUT set to '-', but unable to find atest's PID");
+ return;
+ }
+ path = std::format("/proc/{}/fd/1", ppid);
+ } else {
+ path = ravenwoodLogOut;
+ }
+ ALOGI("RAVENWOOD_LOG_OUT set. Redirecting output to '%s'", path.c_str());
// Redirect stdin / stdout to /dev/tty.
- int ttyFd = open(ravenwoodLogOut, O_WRONLY | O_APPEND);
+ int ttyFd = open(path.c_str(), O_WRONLY | O_APPEND);
if (ttyFd == -1) {
- ALOGW("$RAVENWOOD_LOG_OUT is set to %s, but failed to open: %s ", ravenwoodLogOut,
+ ALOGW("$RAVENWOOD_LOG_OUT is set, but failed to open '%s': %s ", path.c_str(),
strerror(errno));
return;
}
diff --git a/ravenwood/texts/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt
index 91fd9283aff2..0edc348fc7f2 100644
--- a/ravenwood/texts/ravenwood-standard-options.txt
+++ b/ravenwood/texts/ravenwood-standard-options.txt
@@ -9,8 +9,10 @@
# Uncomment below lines to enable each feature.
+# Enable method call hook.
#--default-method-call-hook
-# com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+# android.platform.test.ravenwood.RavenwoodMethodCallLogger.logMethodCall
+
#--default-class-load-hook
# com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
diff --git a/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
index 78fd8f7f960a..145325ccc809 100644
--- a/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
+++ b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
@@ -18,6 +18,7 @@ package com.android.hoststubgen.hosthelper;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
/**
* Utilities used in the host side test environment.
@@ -36,9 +37,14 @@ public class HostTestUtils {
public static final String CLASS_INTERNAL_NAME = getInternalName(HostTestUtils.class);
+ /** If true, we skip all method call hooks */
+ private static final boolean SKIP_METHOD_CALL_HOOK = "1".equals(System.getenv(
+ "HOSTTEST_SKIP_METHOD_CALL_HOOK"));
+
/** If true, we won't print method call log. */
- private static final boolean SKIP_METHOD_LOG = "1".equals(System.getenv(
- "HOSTTEST_SKIP_METHOD_LOG"));
+ private static final boolean SKIP_METHOD_LOG =
+ "1".equals(System.getenv("HOSTTEST_SKIP_METHOD_LOG"))
+ || "1".equals(System.getenv("RAVENWOOD_NO_METHOD_LOG"));
/** If true, we won't print class load log. */
private static final boolean SKIP_CLASS_LOG = "1".equals(System.getenv(
@@ -65,6 +71,9 @@ public class HostTestUtils {
+ "consider using Mockito; more details at go/ravenwood-docs");
}
+ private static final Class<?>[] sMethodHookArgTypes =
+ { Class.class, String.class, String.class};
+
/**
* Trampoline method for method-call-hook.
*/
@@ -74,16 +83,22 @@ public class HostTestUtils {
String methodDescriptor,
String callbackMethod
) {
- callStaticMethodByName(callbackMethod, "method call hook", methodClass,
- methodName, methodDescriptor);
+ if (SKIP_METHOD_CALL_HOOK) {
+ return;
+ }
+ callStaticMethodByName(callbackMethod, "method call hook", sMethodHookArgTypes,
+ methodClass, methodName, methodDescriptor);
}
/**
+ * Simple implementation of method call hook, which just prints the information of the
+ * method. This is just for basic testing. We don't use it in Ravenwood, because this would
+ * be way too noisy as it prints every single method, even trivial ones. (iterator methods,
+ * etc..)
+ *
* I can be used as
* {@code --default-method-call-hook
* com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall}.
- *
- * It logs every single methods called.
*/
public static void logMethodCall(
Class<?> methodClass,
@@ -97,6 +112,8 @@ public class HostTestUtils {
+ methodName + methodDescriptor);
}
+ private static final Class<?>[] sClassLoadHookArgTypes = { Class.class };
+
/**
* Called when any top level class (not nested classes) in the impl jar is loaded.
*
@@ -111,11 +128,12 @@ public class HostTestUtils {
logPrintStream.println("! Class loaded: " + loadedClass.getCanonicalName()
+ " calling hook " + callbackMethod);
- callStaticMethodByName(callbackMethod, "class load hook", loadedClass);
+ callStaticMethodByName(
+ callbackMethod, "class load hook", sClassLoadHookArgTypes, loadedClass);
}
private static void callStaticMethodByName(String classAndMethodName,
- String description, Object... args) {
+ String description, Class<?>[] argTypes, Object... args) {
// Forward the call to callbackMethod.
final int lastPeriod = classAndMethodName.lastIndexOf(".");
@@ -145,19 +163,14 @@ public class HostTestUtils {
className));
}
- Class<?>[] argTypes = new Class[args.length];
- for (int i = 0; i < args.length; i++) {
- argTypes[i] = args[i].getClass();
- }
-
Method method = null;
try {
method = clazz.getMethod(methodName, argTypes);
} catch (Exception e) {
throw new HostTestException(String.format(
"Unable to find %s: class %s doesn't have method %s"
- + " (method must take exactly one parameter of type Class,"
- + " and public static)",
+ + " Method must be public static, and arg types must be: "
+ + Arrays.toString(argTypes),
description, className, methodName), e);
}
if (!(Modifier.isPublic(method.getModifiers())
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 985947575a86..3340990f4765 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -145,6 +145,7 @@ class HostStubGen(val options: HostStubGenOptions) {
// Inject default hooks from options.
filter = DefaultHookInjectingFilter(
+ allClasses,
options.defaultClassLoadHook.get,
options.defaultMethodCallHook.get,
filter
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
index d771003a955d..aaf49c154a17 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
@@ -16,8 +16,11 @@
package com.android.hoststubgen.filters
import com.android.hoststubgen.addLists
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.isAnnotation
class DefaultHookInjectingFilter(
+ val classes: ClassNodes,
defaultClassLoadHook: String?,
defaultMethodCallHook: String?,
fallback: OutputFilter
@@ -36,8 +39,30 @@ class DefaultHookInjectingFilter(
private val defaultClassLoadHookAsList: List<String> = toSingleList(defaultClassLoadHook)
private val defaultMethodCallHookAsList: List<String> = toSingleList(defaultMethodCallHook)
+ private fun shouldInject(className: String): Boolean {
+ // Let's not inject default hooks to annotation classes or inner classes of an annotation
+ // class, because these methods could be called at the class load time, which
+ // is very confusing, and usually not useful.
+
+ val cn = classes.findClass(className) ?: return false
+ if (cn.isAnnotation()) {
+ return false
+ }
+ cn.nestHostClass?.let { nestHostClass ->
+ val nestHost = classes.findClass(nestHostClass) ?: return false
+ if (nestHost.isAnnotation()) {
+ return false
+ }
+ }
+ return true
+ }
+
override fun getClassLoadHooks(className: String): List<String> {
- return addLists(super.getClassLoadHooks(className), defaultClassLoadHookAsList)
+ val s = super.getClassLoadHooks(className)
+ if (!shouldInject(className)) {
+ return s
+ }
+ return addLists(s, defaultClassLoadHookAsList)
}
override fun getMethodCallHooks(
@@ -45,9 +70,23 @@ class DefaultHookInjectingFilter(
methodName: String,
descriptor: String
): List<String> {
- return addLists(
- super.getMethodCallHooks(className, methodName, descriptor),
- defaultMethodCallHookAsList,
- )
+ val s = super.getMethodCallHooks(className, methodName, descriptor)
+ if (!shouldInject(className)) {
+ return s
+ }
+ // Don't hook Object methods.
+ if (methodName == "finalize" && descriptor == "()V") {
+ return s
+ }
+ if (methodName == "toString" && descriptor == "()Ljava/lang/String;") {
+ return s
+ }
+ if (methodName == "equals" && descriptor == "(Ljava/lang/Object;)Z") {
+ return s
+ }
+ if (methodName == "hashCode" && descriptor == "()I") {
+ return s
+ }
+ return addLists(s, defaultMethodCallHookAsList)
}
-} \ No newline at end of file
+}
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
index 49769e648bbf..fb225ff1aa21 100644
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
@@ -6,17 +6,9 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestClassLoadHook
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String value();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -44,16 +36,9 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestKeep.java"
RuntimeVisibleAnnotations:
@@ -75,16 +60,9 @@ public interface android.hosttest.annotation.HostSideTestRedirect extends java.l
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRedirect
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRedirect
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestRedirect.java"
RuntimeVisibleAnnotations:
@@ -106,17 +84,9 @@ public interface android.hosttest.annotation.HostSideTestRedirectionClass extend
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRedirectionClass
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String value();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -144,16 +114,9 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRemove
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRemove
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestRemove.java"
RuntimeVisibleAnnotations:
@@ -175,16 +138,9 @@ public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep e
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestStaticInitializerKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestStaticInitializerKeep.java"
RuntimeVisibleAnnotations:
@@ -206,17 +162,9 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestSubstitute
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestSubstitute
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String suffix();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -244,16 +192,9 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestThrow
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestThrow
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestThrow.java"
RuntimeVisibleAnnotations:
@@ -275,16 +216,9 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestWholeClassKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestWholeClassKeep.java"
RuntimeVisibleAnnotations:
diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
index 0f8af92dc486..e4b9db2ed6d8 100644
--- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
+++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
@@ -6,17 +6,9 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestClassLoadHook
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String value();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -44,16 +36,9 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestKeep.java"
RuntimeVisibleAnnotations:
@@ -75,16 +60,9 @@ public interface android.hosttest.annotation.HostSideTestRedirect extends java.l
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRedirect
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRedirect
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestRedirect.java"
RuntimeVisibleAnnotations:
@@ -106,17 +84,9 @@ public interface android.hosttest.annotation.HostSideTestRedirectionClass extend
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRedirectionClass
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String value();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -144,16 +114,9 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestRemove
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestRemove
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestRemove.java"
RuntimeVisibleAnnotations:
@@ -175,16 +138,9 @@ public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep e
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestStaticInitializerKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestStaticInitializerKeep.java"
RuntimeVisibleAnnotations:
@@ -206,17 +162,9 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestSubstitute
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 2, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestSubstitute
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
public abstract java.lang.String suffix();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
@@ -244,16 +192,9 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestThrow
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestThrow
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestThrow.java"
RuntimeVisibleAnnotations:
@@ -275,16 +216,9 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep
super_class: #x // java/lang/Object
- interfaces: 1, fields: 0, methods: 1, attributes: 2
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestWholeClassKeep
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+Constant pool:
+{
}
SourceFile: "HostSideTestWholeClassKeep.java"
RuntimeVisibleAnnotations:
@@ -307,6 +241,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro
this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -377,6 +313,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -447,6 +385,8 @@ public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -476,6 +416,8 @@ public class com.android.hoststubgen.test.tinyframework.R$Nested
this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 2, attributes: 4
+Constant pool:
+{
public static int[] ARRAY;
descriptor: [I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
@@ -546,6 +488,8 @@ public class com.android.hoststubgen.test.tinyframework.R
this_class: #x // com/android/hoststubgen/test/tinyframework/R
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 2, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -594,6 +538,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 7, attributes: 3
+Constant pool:
+{
public int keep;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -785,6 +731,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 3, attributes: 3
+Constant pool:
+{
public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
descriptor: Ljava/util/Set;
flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
@@ -880,6 +828,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAn
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 5, attributes: 3
+Constant pool:
+{
public int keep;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -1010,6 +960,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 0, attributes: 3
+Constant pool:
+{
public static boolean sInitialized;
descriptor: Z
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
@@ -1047,6 +999,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 1, attributes: 3
+Constant pool:
+{
public static boolean sInitialized;
descriptor: Z
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
@@ -1117,6 +1071,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex
super_class: #x // java/lang/Enum
interfaces: 0, fields: 6, methods: 7, attributes: 4
+Constant pool:
+{
public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED;
descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;
flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
@@ -1400,6 +1356,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple
super_class: #x // java/lang/Enum
interfaces: 0, fields: 3, methods: 5, attributes: 4
+Constant pool:
+{
public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT;
descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;
flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
@@ -1576,6 +1534,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -1659,6 +1619,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 15, attributes: 2
+Constant pool:
+{
public int stub;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -1971,6 +1933,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 8, attributes: 6
+Constant pool:
+{
public final java.util.function.Supplier<java.lang.Integer> mSupplier;
descriptor: Ljava/util/function/Supplier;
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
@@ -2201,6 +2165,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 8, attributes: 6
+Constant pool:
+{
public final java.util.function.Supplier<java.lang.Integer> mSupplier;
descriptor: Ljava/util/function/Supplier;
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
@@ -2432,6 +2398,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 4, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -2526,6 +2494,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 5, attributes: 6
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -2665,6 +2635,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 15, attributes: 3
+Constant pool:
+{
int value;
descriptor: I
flags: (0x0000)
@@ -2998,6 +2970,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 8, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3173,6 +3147,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
super_class: #x // java/lang/Object
interfaces: 1, fields: 1, methods: 4, attributes: 6
+Constant pool:
+{
final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
@@ -3278,6 +3254,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 4, attributes: 6
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3369,6 +3347,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
super_class: #x // java/lang/Object
interfaces: 1, fields: 1, methods: 4, attributes: 6
+Constant pool:
+{
final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
@@ -3474,6 +3454,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 4, attributes: 6
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3565,6 +3547,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 2, attributes: 4
+Constant pool:
+{
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3623,6 +3607,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 2, attributes: 4
+Constant pool:
+{
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3694,6 +3680,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 4, attributes: 6
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3786,6 +3774,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 2, attributes: 4
+Constant pool:
+{
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3844,6 +3834,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 3, attributes: 4
+Constant pool:
+{
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3923,6 +3915,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
super_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
interfaces: 0, fields: 0, methods: 2, attributes: 4
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3973,6 +3967,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
super_class: #x // java/lang/Object
interfaces: 0, fields: 2, methods: 4, attributes: 5
+Constant pool:
+{
public final java.util.function.Supplier<java.lang.Integer> mSupplier;
descriptor: Ljava/util/function/Supplier;
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
@@ -4121,6 +4117,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4192,6 +4190,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4263,6 +4263,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.A
this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4286,6 +4288,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4309,6 +4313,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4332,6 +4338,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4355,6 +4363,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4378,6 +4388,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CA
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4401,6 +4413,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CB
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4424,6 +4438,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4447,6 +4463,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4470,6 +4488,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 ex
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3
super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4493,6 +4513,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 im
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4516,6 +4538,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA
super_class: #x // java/lang/Object
interfaces: 2, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4539,6 +4563,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 im
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4562,6 +4588,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 im
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4585,6 +4613,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I1
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4608,6 +4638,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 exte
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I2
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4631,6 +4663,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 exte
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I3
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4654,6 +4688,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IA
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4677,6 +4713,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB
this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IB
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 2
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4700,6 +4738,8 @@ public class com.supported.UnsupportedClass
this_class: #x // com/supported/UnsupportedClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 3, attributes: 3
+Constant pool:
+{
private final int mValue;
descriptor: I
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
@@ -4779,6 +4819,8 @@ public class com.unsupported.UnsupportedClass
this_class: #x // com/unsupported/UnsupportedClass
super_class: #x // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 3
+Constant pool:
+{
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -4854,6 +4896,8 @@ public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFramew
this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed
super_class: #x // java/lang/Object
interfaces: 0, fields: 1, methods: 3, attributes: 3
+Constant pool:
+{
private final int mValue;
descriptor: I
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 529a564ea607..bb0eacb5afa7 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -145,6 +145,13 @@ flag {
}
flag {
+ name: "enable_magnification_follows_mouse_with_pointer_motion_filter"
+ namespace: "accessibility"
+ description: "Whether to enable mouse following using pointer motion filter"
+ bug: "361817142"
+}
+
+flag {
name: "enable_magnification_keyboard_control"
namespace: "accessibility"
description: "Whether to enable keyboard control for magnification"
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
index 5283df5ca7e1..4fa0d506f09e 100644
--- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java
@@ -538,6 +538,11 @@ public class AutoclickController extends BaseEventStreamTransformation {
return mActive;
}
+ @VisibleForTesting
+ long getScheduledClickTimeForTesting() {
+ return mScheduledClickTime;
+ }
+
/**
* Updates delay that should be used when scheduling clicks. The delay will be used only for
* clicks scheduled after this point (pending click tasks are not affected).
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
index cf928e2f3fa4..614b2285d6e0 100644
--- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
@@ -168,6 +168,10 @@ public class AutoclickTypePanel {
}
public void hide() {
+ // Sets the button background to unselected styling, this is necessary to make sure the
+ // button background styling is correct when the panel shows up next time.
+ toggleSelectedButtonStyle(mSelectedButton, /* isSelected= */ false);
+
mWindowManager.removeView(mContentView);
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index d47aab061788..e0f2939a2083 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -16,7 +16,6 @@
package com.android.server.appwidget;
-import static android.appwidget.flags.Flags.checkRemoteViewsUriPermission;
import static android.appwidget.flags.Flags.remoteAdapterConversion;
import static android.appwidget.flags.Flags.remoteViewsProto;
import static android.appwidget.flags.Flags.removeAppWidgetServiceIoFromCriticalPath;
@@ -2560,9 +2559,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// Make sure the package runs under the caller uid.
mSecurityPolicy.enforceCallFromPackage(callingPackage);
// Make sure RemoteViews do not contain URIs that the caller cannot access.
- if (checkRemoteViewsUriPermission()) {
- checkRemoteViewsUris(views);
- }
+ checkRemoteViewsUris(views);
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
index 89c9d690a82c..d8e10f842665 100644
--- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
+++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
@@ -34,9 +34,10 @@ import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUC
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManagerInternal;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.contextualsearch.CallbackToken;
@@ -65,11 +66,11 @@ import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
+import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
import android.view.IWindowManager;
-import android.window.ScreenCapture;
import android.window.ScreenCapture.ScreenshotHardwareBuffer;
import com.android.internal.R;
@@ -86,7 +87,6 @@ import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import java.util.Set;
public class ContextualSearchManagerService extends SystemService {
private static final String TAG = ContextualSearchManagerService.class.getSimpleName();
@@ -95,14 +95,25 @@ public class ContextualSearchManagerService extends SystemService {
private static final int MSG_INVALIDATE_TOKEN = 1;
private static final int MAX_TOKEN_VALID_DURATION_MS = 1_000 * 60 * 10; // 10 minutes
+ /**
+ * Below are internal entrypoints not supported by the
+ * {@link ContextualSearchManager#startContextualSearch(int entrypoint)} method.
+ *
+ * <p>These values should be negative to avoid conflicting with the system entrypoints.
+ */
+
+ /** Entrypoint to be used when a foreground app invokes Contextual Search. */
+ private static final int INTERNAL_ENTRYPOINT_APP = -1;
+
private static final boolean DEBUG = false;
private final Context mContext;
+ private final ActivityManagerInternal mActivityManagerInternal;
private final ActivityTaskManagerInternal mAtmInternal;
private final PackageManagerInternal mPackageManager;
private final WindowManagerInternal mWmInternal;
- private final DevicePolicyManagerInternal mDpmInternal;
private final AudioManager mAudioManager;
+ private final UserManager mUserManager;
private final Object mLock = new Object();
private final AssistDataRequester mAssistDataRequester;
@@ -162,13 +173,15 @@ public class ContextualSearchManagerService extends SystemService {
super(context);
if (DEBUG) Log.d(TAG, "ContextualSearchManagerService created");
mContext = context;
+ mActivityManagerInternal = Objects.requireNonNull(
+ LocalServices.getService(ActivityManagerInternal.class));
mAtmInternal = Objects.requireNonNull(
LocalServices.getService(ActivityTaskManagerInternal.class));
mPackageManager = LocalServices.getService(PackageManagerInternal.class);
mAudioManager = context.getSystemService(AudioManager.class);
+ mUserManager = context.getSystemService(UserManager.class);
mWmInternal = Objects.requireNonNull(LocalServices.getService(WindowManagerInternal.class));
- mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
mAssistDataRequester = new AssistDataRequester(
mContext,
IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)),
@@ -295,6 +308,11 @@ public class ContextualSearchManagerService extends SystemService {
}
}
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS,
+ android.Manifest.permission.QUERY_USERS
+ })
private Intent getContextualSearchIntent(int entrypoint, int userId, CallbackToken mToken) {
final Intent launchIntent = getResolvedLaunchIntent(userId);
if (launchIntent == null) {
@@ -325,8 +343,7 @@ public class ContextualSearchManagerService extends SystemService {
visiblePackageNames.add(record.getComponentName().getPackageName());
activityTokens.add(record.getActivityToken());
}
- if (mDpmInternal != null
- && mDpmInternal.isUserOrganizationManaged(record.getUserId())) {
+ if (mUserManager.isManagedProfile(record.getUserId())) {
isManagedProfileVisible = true;
}
}
@@ -391,6 +408,20 @@ public class ContextualSearchManagerService extends SystemService {
}
}
+ private void enforceForegroundApp(@NonNull final String func) {
+ final int callingUid = Binder.getCallingUid();
+ final String callingPackage = mPackageManager.getNameForUid(Binder.getCallingUid());
+ if (mActivityManagerInternal.getUidProcessState(callingUid)
+ > ActivityManager.PROCESS_STATE_TOP) {
+ // The calling process must be displaying an activity in foreground to
+ // trigger contextual search.
+ String msg = "Permission Denial: Cannot call " + func + " from pid="
+ + Binder.getCallingPid() + ", uid=" + callingUid
+ + ", package=" + callingPackage + " without a foreground activity.";
+ throw new SecurityException(msg);
+ }
+ }
+
private void enforceOverridingPermission(@NonNull final String func) {
if (!(Binder.getCallingUid() == Process.SHELL_UID
|| Binder.getCallingUid() == Process.ROOT_UID
@@ -448,27 +479,44 @@ public class ContextualSearchManagerService extends SystemService {
}
@Override
+ public void startContextualSearchForForegroundApp() {
+ synchronized (this) {
+ if (DEBUG) {
+ Log.d(TAG, "Starting contextual search from: "
+ + mPackageManager.getNameForUid(Binder.getCallingUid()));
+ }
+ enforceForegroundApp("startContextualSearchForForegroundApp");
+ startContextualSearchInternal(INTERNAL_ENTRYPOINT_APP);
+ }
+ }
+
+ @Override
public void startContextualSearch(int entrypoint) {
synchronized (this) {
if (DEBUG) Log.d(TAG, "startContextualSearch entrypoint: " + entrypoint);
enforcePermission("startContextualSearch");
- final int callingUserId = Binder.getCallingUserHandle().getIdentifier();
+ startContextualSearchInternal(entrypoint);
+ }
+ }
- mAssistDataRequester.cancel();
- // Creates a new CallbackToken at mToken and an expiration handler.
- issueToken();
- // We get the launch intent with the system server's identity because the system
- // server has READ_FRAME_BUFFER permission to get the screenshot and because only
- // the system server can invoke non-exported activities.
- Binder.withCleanCallingIdentity(() -> {
- Intent launchIntent =
- getContextualSearchIntent(entrypoint, callingUserId, mToken);
- if (launchIntent != null) {
- int result = invokeContextualSearchIntent(launchIntent, callingUserId);
- if (DEBUG) Log.d(TAG, "Launch result: " + result);
+ private void startContextualSearchInternal(int entrypoint) {
+ final int callingUserId = Binder.getCallingUserHandle().getIdentifier();
+ mAssistDataRequester.cancel();
+ // Creates a new CallbackToken at mToken and an expiration handler.
+ issueToken();
+ // We get the launch intent with the system server's identity because the system
+ // server has READ_FRAME_BUFFER permission to get the screenshot and because only
+ // the system server can invoke non-exported activities.
+ Binder.withCleanCallingIdentity(() -> {
+ Intent launchIntent = getContextualSearchIntent(entrypoint, callingUserId, mToken);
+ if (launchIntent != null) {
+ int result = invokeContextualSearchIntent(launchIntent, callingUserId);
+ if (DEBUG) {
+ Log.d(TAG, "Launch intent: " + launchIntent);
+ Log.d(TAG, "Launch result: " + result);
}
- });
- }
+ }
+ });
}
@Override
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 00db11e72dd9..2aaf6a9c2391 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -300,10 +300,7 @@ java_genrule_combiner {
java_library {
name: "services.core",
- static_libs: select(release_flag("RELEASE_SERVICES_JAVA_GENRULE_COMBINER"), {
- true: ["services.core.combined"],
- default: ["services.core.priorityboosted"],
- }),
+ static_libs: ["services.core.combined"],
}
java_library_host {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 4976a63b016b..8eda17698b9b 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -18,7 +18,6 @@ package com.android.server;
import static android.app.Flags.enableCurrentModeTypeBinderCache;
import static android.app.Flags.enableNightModeBinderCache;
-import static android.app.Flags.modesApi;
import static android.app.UiModeManager.ContrastUtils.CONTRAST_DEFAULT_VALUE;
import static android.app.UiModeManager.DEFAULT_PRIORITY;
import static android.app.UiModeManager.FORCE_INVERT_TYPE_DARK;
@@ -2208,14 +2207,12 @@ final class UiModeManagerService extends SystemService {
appliedOverrides = true;
}
- if (modesApi()) {
- // Computes final night mode values based on Attention Mode.
- mComputedNightMode = switch (mAttentionModeThemeOverlay) {
- case (UiModeManager.MODE_ATTENTION_THEME_OVERLAY_NIGHT) -> true;
- case (UiModeManager.MODE_ATTENTION_THEME_OVERLAY_DAY) -> false;
- default -> newComputedValue; // case OFF
- };
- }
+ // Computes final night mode values based on Attention Mode.
+ mComputedNightMode = switch (mAttentionModeThemeOverlay) {
+ case (UiModeManager.MODE_ATTENTION_THEME_OVERLAY_NIGHT) -> true;
+ case (UiModeManager.MODE_ATTENTION_THEME_OVERLAY_DAY) -> false;
+ default -> newComputedValue; // case OFF
+ };
if (appliedOverrides) {
return;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f34016905502..6e3d7bd19b41 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8315,14 +8315,6 @@ public class ActivityManagerService extends IActivityManager.Stub
setThreadScheduler(proc.getRenderThreadTid(),
SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
} else {
- if (Flags.resetOnForkEnabled()) {
- if (Process.getThreadScheduler(proc.getRenderThreadTid())
- == Process.SCHED_OTHER) {
- Process.setThreadScheduler(proc.getRenderThreadTid(),
- Process.SCHED_OTHER | Process.SCHED_RESET_ON_FORK,
- 0);
- }
- }
setThreadPriority(proc.getRenderThreadTid(),
THREAD_PRIORITY_TOP_APP_BOOST);
}
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index 961022b7231b..517279bd7527 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -54,15 +54,21 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ProcessMap;
import com.android.internal.os.Clock;
import com.android.internal.os.MonotonicClock;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.IoThread;
import com.android.server.ServiceThread;
import com.android.server.SystemServiceManager;
import com.android.server.wm.WindowProcessController;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -1006,6 +1012,12 @@ public final class AppStartInfoTracker {
throws IOException, WireTypeMismatchException, ClassNotFoundException {
long token = proto.start(fieldId);
String pkgName = "";
+
+ // Create objects for reuse.
+ ByteArrayInputStream byteArrayInputStream = null;
+ ObjectInputStream objectInputStream = null;
+ TypedXmlPullParser typedXmlPullParser = null;
+
for (int next = proto.nextField();
next != ProtoInputStream.NO_MORE_FIELDS;
next = proto.nextField()) {
@@ -1017,7 +1029,7 @@ public final class AppStartInfoTracker {
AppStartInfoContainer container =
new AppStartInfoContainer(mAppStartInfoHistoryListSize);
int uid = container.readFromProto(proto, AppsStartInfoProto.Package.USERS,
- pkgName);
+ pkgName, byteArrayInputStream, objectInputStream, typedXmlPullParser);
// If the isolated process flag is enabled and the uid is that of an isolated
// process, then break early so that the container will not be added to mData.
@@ -1052,6 +1064,12 @@ public final class AppStartInfoTracker {
out = af.startWrite();
ProtoOutputStream proto = new ProtoOutputStream(out);
proto.write(AppsStartInfoProto.LAST_UPDATE_TIMESTAMP, now);
+
+ // Create objects for reuse.
+ ByteArrayOutputStream byteArrayOutputStream = null;
+ ObjectOutputStream objectOutputStream = null;
+ TypedXmlSerializer typedXmlSerializer = null;
+
synchronized (mLock) {
succeeded = forEachPackageLocked(
(packageName, records) -> {
@@ -1060,8 +1078,9 @@ public final class AppStartInfoTracker {
int uidArraySize = records.size();
for (int j = 0; j < uidArraySize; j++) {
try {
- records.valueAt(j)
- .writeToProto(proto, AppsStartInfoProto.Package.USERS);
+ records.valueAt(j).writeToProto(proto,
+ AppsStartInfoProto.Package.USERS, byteArrayOutputStream,
+ objectOutputStream, typedXmlSerializer);
} catch (IOException e) {
Slog.w(TAG, "Unable to write app start info into persistent"
+ "storage: " + e);
@@ -1414,19 +1433,23 @@ public final class AppStartInfoTracker {
}
@GuardedBy("mLock")
- void writeToProto(ProtoOutputStream proto, long fieldId) throws IOException {
+ void writeToProto(ProtoOutputStream proto, long fieldId,
+ ByteArrayOutputStream byteArrayOutputStream, ObjectOutputStream objectOutputStream,
+ TypedXmlSerializer typedXmlSerializer) throws IOException {
long token = proto.start(fieldId);
proto.write(AppsStartInfoProto.Package.User.UID, mUid);
int size = mInfos.size();
for (int i = 0; i < size; i++) {
- mInfos.get(i)
- .writeToProto(proto, AppsStartInfoProto.Package.User.APP_START_INFO);
+ mInfos.get(i).writeToProto(proto, AppsStartInfoProto.Package.User.APP_START_INFO,
+ byteArrayOutputStream, objectOutputStream, typedXmlSerializer);
}
proto.write(AppsStartInfoProto.Package.User.MONITORING_ENABLED, mMonitoringModeEnabled);
proto.end(token);
}
- int readFromProto(ProtoInputStream proto, long fieldId, String packageName)
+ int readFromProto(ProtoInputStream proto, long fieldId, String packageName,
+ ByteArrayInputStream byteArrayInputStream, ObjectInputStream objectInputStream,
+ TypedXmlPullParser typedXmlPullParser)
throws IOException, WireTypeMismatchException, ClassNotFoundException {
long token = proto.start(fieldId);
for (int next = proto.nextField();
@@ -1440,7 +1463,8 @@ public final class AppStartInfoTracker {
// Create record with monotonic time 0 in case the persisted record does not
// have a create time.
ApplicationStartInfo info = new ApplicationStartInfo(0);
- info.readFromProto(proto, AppsStartInfoProto.Package.User.APP_START_INFO);
+ info.readFromProto(proto, AppsStartInfoProto.Package.User.APP_START_INFO,
+ byteArrayInputStream, objectInputStream, typedXmlPullParser);
info.setPackageName(packageName);
mInfos.add(info);
break;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index cd40905b01da..61c5501a7b5a 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -471,13 +471,6 @@ public class OomAdjuster {
}
void setThreadPriority(int tid, int priority) {
- if (Flags.resetOnForkEnabled()) {
- if (Process.getThreadScheduler(tid) == Process.SCHED_OTHER) {
- Process.setThreadScheduler(tid,
- Process.SCHED_OTHER | Process.SCHED_RESET_ON_FORK,
- 0);
- }
- }
Process.setThreadPriority(tid, priority);
}
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 27e9e44f1090..e0fbaf43ea43 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -31,6 +31,7 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
+import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -3904,10 +3905,6 @@ class UserController implements Handler.Callback {
return mService.mWindowManager;
}
- ActivityTaskManagerInternal getActivityTaskManagerInternal() {
- return mService.mAtmInternal;
- }
-
void activityManagerOnUserStopped(@UserIdInt int userId) {
LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId);
}
@@ -4122,40 +4119,25 @@ class UserController implements Handler.Callback {
}
void lockDeviceNowAndWaitForKeyguardShown() {
- if (getWindowManager().isKeyguardLocked()) {
- Slogf.w(TAG, "Not locking the device since the keyguard is already locked");
- return;
- }
-
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("lockDeviceNowAndWaitForKeyguardShown");
final CountDownLatch latch = new CountDownLatch(1);
- ActivityTaskManagerInternal.ScreenObserver screenObserver =
- new ActivityTaskManagerInternal.ScreenObserver() {
- @Override
- public void onAwakeStateChanged(boolean isAwake) {
-
- }
-
- @Override
- public void onKeyguardStateChanged(boolean isShowing) {
- if (isShowing) {
- latch.countDown();
- }
- }
- };
-
- getActivityTaskManagerInternal().registerScreenObserver(screenObserver);
- getWindowManager().lockDeviceNow();
+ Bundle bundle = new Bundle();
+ bundle.putBinder(LOCK_ON_USER_SWITCH_CALLBACK, new IRemoteCallback.Stub() {
+ public void sendResult(Bundle data) {
+ latch.countDown();
+ }
+ });
+ getWindowManager().lockNow(bundle);
try {
if (!latch.await(20, TimeUnit.SECONDS)) {
- throw new RuntimeException("Keyguard is not shown in 20 seconds");
+ throw new RuntimeException("User controller expected a callback while waiting "
+ + "to show the keyguard. Timed out after 20 seconds.");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
- getActivityTaskManagerInternal().unregisterScreenObserver(screenObserver);
t.traceEnd();
}
}
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index e89889e794ba..27c384a22fb6 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -205,13 +205,6 @@ flag {
}
flag {
- name: "reset_on_fork_enabled"
- namespace: "system_performance"
- description: "Set reset_on_fork flag."
- bug: "370988407"
-}
-
-flag {
name: "push_global_state_to_oomadjuster"
namespace: "backstage_power"
description: "Migrate OomAdjuster pulled device state to a push model"
@@ -319,3 +312,14 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "lower_sms_oom_importance"
+ namespace: "backstage_power"
+ description: "Lower messaging app process oom importance to PERCEPTIBLE_APP_ADJ + 1."
+ bug: "372511805"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/appbinding/AppBindingConstants.java b/services/core/java/com/android/server/appbinding/AppBindingConstants.java
index 71847694b1d8..561cc0ef0a3b 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingConstants.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingConstants.java
@@ -102,9 +102,16 @@ public class AppBindingConstants {
boolean smsServiceEnabled = parser.getBoolean(SMS_SERVICE_ENABLED_KEY, true);
- int smsAppBindFlags = parser.getInt(
- SMS_APP_BIND_FLAGS_KEY,
- Context.BIND_NOT_VISIBLE | Context.BIND_FOREGROUND_SERVICE);
+ int smsAppBindFlags;
+ if (com.android.server.am.Flags.lowerSmsOomImportance()) {
+ smsAppBindFlags = parser.getInt(
+ SMS_APP_BIND_FLAGS_KEY,
+ Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_FOREGROUND_SERVICE);
+ } else {
+ smsAppBindFlags = parser.getInt(
+ SMS_APP_BIND_FLAGS_KEY,
+ Context.BIND_NOT_VISIBLE | Context.BIND_FOREGROUND_SERVICE);
+ }
long serviceStableConnectionThresholdSec = parser.getLong(
SERVICE_STABLE_CONNECTION_THRESHOLD_SEC_KEY, TimeUnit.MINUTES.toSeconds(2));
diff --git a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java
index 30c2a82296ca..604cb30294a9 100644
--- a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java
@@ -418,7 +418,9 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
evictedEvents.addAll(mCache);
mCache.clear();
}
- mSqliteWriteHandler.obtainMessage(WRITE_CACHE_EVICTED_OP_EVENTS, evictedEvents);
+ Message msg = mSqliteWriteHandler.obtainMessage(
+ WRITE_CACHE_EVICTED_OP_EVENTS, evictedEvents);
+ mSqliteWriteHandler.sendMessage(msg);
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 4ec813827cbc..ef80d59993e9 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -18,6 +18,7 @@ package com.android.server.audio;
import static android.media.audio.Flags.scoManagedByAudio;
import static com.android.media.audio.Flags.equalScoLeaVcIndexRange;
+import static com.android.media.audio.Flags.optimizeBtDeviceSwitch;
import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_HEADSET;
import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER;
import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_SCO;
@@ -290,8 +291,8 @@ public class AudioDeviceBroker {
}
@GuardedBy("mDeviceStateLock")
- /*package*/ void onSetBtScoActiveDevice(BluetoothDevice btDevice) {
- mBtHelper.onSetBtScoActiveDevice(btDevice);
+ /*package*/ void onSetBtScoActiveDevice(BluetoothDevice btDevice, boolean deviceSwitch) {
+ mBtHelper.onSetBtScoActiveDevice(btDevice, deviceSwitch);
}
/*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) {
@@ -941,6 +942,7 @@ public class AudioDeviceBroker {
final @NonNull String mEventSource;
final int mAudioSystemDevice;
final int mMusicDevice;
+ final boolean mIsDeviceSwitch;
BtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state,
int audioDevice, @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) {
@@ -953,6 +955,8 @@ public class AudioDeviceBroker {
mEventSource = d.mEventSource;
mAudioSystemDevice = audioDevice;
mMusicDevice = AudioSystem.DEVICE_NONE;
+ mIsDeviceSwitch = optimizeBtDeviceSwitch()
+ && d.mNewDevice != null && d.mPreviousDevice != null;
}
// constructor used by AudioDeviceBroker to search similar message
@@ -966,6 +970,7 @@ public class AudioDeviceBroker {
mSupprNoisy = false;
mVolume = -1;
mIsLeOutput = false;
+ mIsDeviceSwitch = false;
}
// constructor used by AudioDeviceInventory when config change failed
@@ -980,6 +985,7 @@ public class AudioDeviceBroker {
mSupprNoisy = false;
mVolume = -1;
mIsLeOutput = false;
+ mIsDeviceSwitch = false;
}
BtDeviceInfo(@NonNull BtDeviceInfo src, int state) {
@@ -992,6 +998,7 @@ public class AudioDeviceBroker {
mEventSource = src.mEventSource;
mAudioSystemDevice = src.mAudioSystemDevice;
mMusicDevice = src.mMusicDevice;
+ mIsDeviceSwitch = false;
}
// redefine equality op so we can match messages intended for this device
@@ -1026,42 +1033,15 @@ public class AudioDeviceBroker {
+ " isLeOutput=" + mIsLeOutput
+ " eventSource=" + mEventSource
+ " audioSystemDevice=" + mAudioSystemDevice
- + " musicDevice=" + mMusicDevice;
- }
- }
-
- BtDeviceInfo createBtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device,
- int state) {
- int audioDevice;
- int codec = AudioSystem.AUDIO_FORMAT_DEFAULT;
- switch (d.mInfo.getProfile()) {
- case BluetoothProfile.A2DP_SINK:
- audioDevice = AudioSystem.DEVICE_IN_BLUETOOTH_A2DP;
- break;
- case BluetoothProfile.A2DP:
- audioDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
- break;
- case BluetoothProfile.HEARING_AID:
- audioDevice = AudioSystem.DEVICE_OUT_HEARING_AID;
- break;
- case BluetoothProfile.LE_AUDIO:
- if (d.mInfo.isLeOutput()) {
- audioDevice = AudioSystem.DEVICE_OUT_BLE_HEADSET;
- } else {
- audioDevice = AudioSystem.DEVICE_IN_BLE_HEADSET;
- }
- break;
- case BluetoothProfile.LE_AUDIO_BROADCAST:
- audioDevice = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
- break;
- case BluetoothProfile.HEADSET:
- // the actual device type is not important at this point and
- // will be set by BtHelper.handleBtScoActiveDeviceChange()
- audioDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
- break;
- default: throw new IllegalArgumentException("Invalid profile " + d.mInfo.getProfile());
+ + " musicDevice=" + mMusicDevice
+ + " isDeviceSwitch=" + mIsDeviceSwitch;
}
- return new BtDeviceInfo(d, device, state, audioDevice, codec);
+ }
+
+ /*package*/ static BtDeviceInfo createBtDeviceInfo(@NonNull BtDeviceChangedData d,
+ @NonNull BluetoothDevice device, int state) {
+ int audioDevice = BtHelper.getTypeFromProfile(d.mInfo.getProfile(), d.mInfo.isLeOutput());
+ return new BtDeviceInfo(d, device, state, audioDevice, AudioSystem.AUDIO_FORMAT_DEFAULT);
}
private void btMediaMetricRecord(@NonNull BluetoothDevice device, String state,
@@ -1224,6 +1204,8 @@ public class AudioDeviceBroker {
AudioSystem.setParameters("A2dpSuspended=true");
AudioSystem.setParameters("LeAudioSuspended=true");
AudioSystem.setParameters("BT_SCO=on");
+ mBluetoothA2dpSuspendedApplied = true;
+ mBluetoothLeSuspendedApplied = true;
} else {
AudioSystem.setParameters("BT_SCO=off");
if (mBluetoothA2dpSuspendedApplied) {
@@ -1708,10 +1690,11 @@ public class AudioDeviceBroker {
}
/*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes,
- boolean connect, @Nullable BluetoothDevice btDevice) {
+ boolean connect, @Nullable BluetoothDevice btDevice,
+ boolean deviceSwitch) {
synchronized (mDeviceStateLock) {
return mDeviceInventory.handleDeviceConnection(
- attributes, connect, false /*for test*/, btDevice);
+ attributes, connect, false /*for test*/, btDevice, deviceSwitch);
}
}
@@ -1728,8 +1711,8 @@ public class AudioDeviceBroker {
}
// must be called synchronized on mConnectedDevices
- /*package*/ boolean hasScheduledA2dpConnection(BluetoothDevice btDevice) {
- final BtDeviceInfo devInfoToCheck = new BtDeviceInfo(btDevice, BluetoothProfile.A2DP);
+ /*package*/ boolean hasScheduledA2dpConnection(BluetoothDevice btDevice, int profile) {
+ final BtDeviceInfo devInfoToCheck = new BtDeviceInfo(btDevice, profile);
return mBrokerHandler.hasEqualMessages(MSG_L_SET_BT_ACTIVE_DEVICE, devInfoToCheck);
}
@@ -1804,6 +1787,18 @@ public class AudioDeviceBroker {
pw.println("\n" + prefix + "mScoManagedByAudio: " + mScoManagedByAudio);
+ pw.println("\n" + prefix + "Bluetooth SCO on"
+ + ", requested: " + mBluetoothScoOn
+ + ", applied: " + mBluetoothScoOnApplied);
+ pw.println("\n" + prefix + "Bluetooth A2DP suspended"
+ + ", requested ext: " + mBluetoothA2dpSuspendedExt
+ + ", requested int: " + mBluetoothA2dpSuspendedInt
+ + ", applied " + mBluetoothA2dpSuspendedApplied);
+ pw.println("\n" + prefix + "Bluetooth LE Audio suspended"
+ + ", requested ext: " + mBluetoothLeSuspendedExt
+ + ", requested int: " + mBluetoothLeSuspendedInt
+ + ", applied " + mBluetoothLeSuspendedApplied);
+
mBtHelper.dump(pw, prefix);
}
@@ -1958,10 +1953,12 @@ public class AudioDeviceBroker {
|| btInfo.mIsLeOutput)
? mAudioService.getBluetoothContextualVolumeStream()
: AudioSystem.STREAM_DEFAULT);
- if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
+ if ((btInfo.mProfile == BluetoothProfile.LE_AUDIO
|| btInfo.mProfile == BluetoothProfile.HEARING_AID
|| (mScoManagedByAudio
- && btInfo.mProfile == BluetoothProfile.HEADSET)) {
+ && btInfo.mProfile == BluetoothProfile.HEADSET))
+ && (btInfo.mState == BluetoothProfile.STATE_CONNECTED
+ || !btInfo.mIsDeviceSwitch)) {
onUpdateCommunicationRouteClient(
bluetoothScoRequestOwnerAttributionSource(),
"setBluetoothActiveDevice");
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 37ef9a0648a6..ae91934e7498 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -799,7 +799,7 @@ public class AudioDeviceInventory {
di.mDeviceAddress,
di.mDeviceName),
AudioSystem.DEVICE_STATE_AVAILABLE,
- di.mDeviceCodecFormat);
+ di.mDeviceCodecFormat, false /*deviceSwitch*/);
if (asDeviceConnectionFailure() && res != AudioSystem.AUDIO_STATUS_OK) {
failedReconnectionDeviceList.add(di);
}
@@ -811,7 +811,7 @@ public class AudioDeviceInventory {
EventLogger.Event.ALOGE, TAG);
mConnectedDevices.remove(di.getKey(), di);
if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
- mDeviceBroker.onSetBtScoActiveDevice(null);
+ mDeviceBroker.onSetBtScoActiveDevice(null, false /*deviceSwitch*/);
}
}
}
@@ -851,7 +851,8 @@ public class AudioDeviceInventory {
Log.d(TAG, "onSetBtActiveDevice"
+ " btDevice=" + btInfo.mDevice
+ " profile=" + BluetoothProfile.getProfileName(btInfo.mProfile)
- + " state=" + BluetoothProfile.getConnectionStateName(btInfo.mState));
+ + " state=" + BluetoothProfile.getConnectionStateName(btInfo.mState)
+ + " isDeviceSwitch=" + btInfo.mIsDeviceSwitch);
}
String address = btInfo.mDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -897,7 +898,8 @@ public class AudioDeviceInventory {
break;
case BluetoothProfile.A2DP:
if (switchToUnavailable) {
- makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
+ makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat,
+ btInfo.mIsDeviceSwitch);
} else if (switchToAvailable) {
// device is not already connected
if (btInfo.mVolume != -1) {
@@ -911,7 +913,7 @@ public class AudioDeviceInventory {
break;
case BluetoothProfile.HEARING_AID:
if (switchToUnavailable) {
- makeHearingAidDeviceUnavailable(address);
+ makeHearingAidDeviceUnavailable(address, btInfo.mIsDeviceSwitch);
} else if (switchToAvailable) {
makeHearingAidDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
streamType, "onSetBtActiveDevice");
@@ -921,7 +923,8 @@ public class AudioDeviceInventory {
case BluetoothProfile.LE_AUDIO_BROADCAST:
if (switchToUnavailable) {
makeLeAudioDeviceUnavailableNow(address,
- btInfo.mAudioSystemDevice, di.mDeviceCodecFormat);
+ btInfo.mAudioSystemDevice, di.mDeviceCodecFormat,
+ btInfo.mIsDeviceSwitch);
} else if (switchToAvailable) {
makeLeAudioDeviceAvailable(
btInfo, streamType, codec, "onSetBtActiveDevice");
@@ -930,9 +933,10 @@ public class AudioDeviceInventory {
case BluetoothProfile.HEADSET:
if (mDeviceBroker.isScoManagedByAudio()) {
if (switchToUnavailable) {
- mDeviceBroker.onSetBtScoActiveDevice(null);
+ mDeviceBroker.onSetBtScoActiveDevice(null, btInfo.mIsDeviceSwitch);
} else if (switchToAvailable) {
- mDeviceBroker.onSetBtScoActiveDevice(btInfo.mDevice);
+ mDeviceBroker.onSetBtScoActiveDevice(
+ btInfo.mDevice, false /*deviceSwitch*/);
}
}
break;
@@ -987,8 +991,10 @@ public class AudioDeviceInventory {
"onBluetoothDeviceConfigChange addr=" + address
+ " event=" + BtHelper.deviceEventToString(event)));
+ int deviceType = BtHelper.getTypeFromProfile(btInfo.mProfile, btInfo.mIsLeOutput);
+
synchronized (mDevicesLock) {
- if (mDeviceBroker.hasScheduledA2dpConnection(btDevice)) {
+ if (mDeviceBroker.hasScheduledA2dpConnection(btDevice, btInfo.mProfile)) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"A2dp config change ignored (scheduled connection change)")
.printSlog(EventLogger.Event.ALOGI, TAG));
@@ -996,8 +1002,7 @@ public class AudioDeviceInventory {
.record();
return delayMs;
}
- final String key = DeviceInfo.makeDeviceListKey(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
+ final String key = DeviceInfo.makeDeviceListKey(deviceType, address);
final DeviceInfo di = mConnectedDevices.get(key);
if (di == null) {
Log.e(TAG, "invalid null DeviceInfo in onBluetoothDeviceConfigChange");
@@ -1022,7 +1027,7 @@ public class AudioDeviceInventory {
BtHelper.getName(btDevice), codec);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "APM handleDeviceConfigChange failed for A2DP device addr="
+ "APM handleDeviceConfigChange failed for device addr="
+ address + " codec="
+ AudioSystem.audioFormatToString(codec))
.printSlog(EventLogger.Event.ALOGE, TAG));
@@ -1033,7 +1038,7 @@ public class AudioDeviceInventory {
BluetoothProfile.STATE_DISCONNECTED));
} else {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "APM handleDeviceConfigChange success for A2DP device addr="
+ "APM handleDeviceConfigChange success for device addr="
+ address
+ " codec=" + AudioSystem.audioFormatToString(codec))
.printSlog(EventLogger.Event.ALOGI, TAG));
@@ -1052,19 +1057,19 @@ public class AudioDeviceInventory {
/*package*/ void onMakeA2dpDeviceUnavailableNow(String address, int a2dpCodec) {
synchronized (mDevicesLock) {
- makeA2dpDeviceUnavailableNow(address, a2dpCodec);
+ makeA2dpDeviceUnavailableNow(address, a2dpCodec, false /*deviceSwitch*/);
}
}
/*package*/ void onMakeLeAudioDeviceUnavailableNow(String address, int device, int codec) {
synchronized (mDevicesLock) {
- makeLeAudioDeviceUnavailableNow(address, device, codec);
+ makeLeAudioDeviceUnavailableNow(address, device, codec, false /*deviceSwitch*/);
}
}
/*package*/ void onMakeHearingAidDeviceUnavailableNow(String address) {
synchronized (mDevicesLock) {
- makeHearingAidDeviceUnavailable(address);
+ makeHearingAidDeviceUnavailable(address, false /*deviceSwitch*/);
}
}
@@ -1179,7 +1184,8 @@ public class AudioDeviceInventory {
}
if (!handleDeviceConnection(wdcs.mAttributes,
- wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest, null)) {
+ wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest,
+ null, false /*deviceSwitch*/)) {
// change of connection state failed, bailout
mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")
.record();
@@ -1787,14 +1793,15 @@ public class AudioDeviceInventory {
*/
/*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes,
boolean connect, boolean isForTesting,
- @Nullable BluetoothDevice btDevice) {
+ @Nullable BluetoothDevice btDevice,
+ boolean deviceSwitch) {
int device = attributes.getInternalType();
String address = attributes.getAddress();
String deviceName = attributes.getName();
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:"
+ Integer.toHexString(device) + " address:" + address
- + " name:" + deviceName + ")");
+ + " name:" + deviceName + ", deviceSwitch: " + deviceSwitch + ")");
}
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "handleDeviceConnection")
.set(MediaMetrics.Property.ADDRESS, address)
@@ -1828,7 +1835,8 @@ public class AudioDeviceInventory {
res = AudioSystem.AUDIO_STATUS_OK;
} else {
res = mAudioSystem.setDeviceConnectionState(attributes,
- AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT,
+ false /*deviceSwitch*/);
}
if (res != AudioSystem.AUDIO_STATUS_OK) {
final String reason = "not connecting device 0x" + Integer.toHexString(device)
@@ -1855,7 +1863,8 @@ public class AudioDeviceInventory {
status = true;
} else if (!connect && isConnected) {
mAudioSystem.setDeviceConnectionState(attributes,
- AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT,
+ deviceSwitch);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
mDeviceBroker.postCheckCommunicationDeviceRemoval(attributes);
@@ -2029,7 +2038,7 @@ public class AudioDeviceInventory {
}
}
if (disconnect) {
- mDeviceBroker.onSetBtScoActiveDevice(null);
+ mDeviceBroker.onSetBtScoActiveDevice(null, false /*deviceSwitch*/);
}
}
@@ -2067,7 +2076,8 @@ public class AudioDeviceInventory {
|| info.mProfile == BluetoothProfile.LE_AUDIO_BROADCAST)
&& info.mIsLeOutput)
|| info.mProfile == BluetoothProfile.HEARING_AID
- || info.mProfile == BluetoothProfile.A2DP)) {
+ || info.mProfile == BluetoothProfile.A2DP)
+ && !info.mIsDeviceSwitch) {
@AudioService.ConnectionState int asState =
(info.mState == BluetoothProfile.STATE_CONNECTED)
? AudioService.CONNECTION_STATE_CONNECTED
@@ -2123,7 +2133,7 @@ public class AudioDeviceInventory {
AudioDeviceAttributes ada = new AudioDeviceAttributes(
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name);
final int res = mAudioSystem.setDeviceConnectionState(ada,
- AudioSystem.DEVICE_STATE_AVAILABLE, codec);
+ AudioSystem.DEVICE_STATE_AVAILABLE, codec, false);
// TODO: log in MediaMetrics once distinction between connection failure and
// double connection is made.
@@ -2361,7 +2371,7 @@ public class AudioDeviceInventory {
}
@GuardedBy("mDevicesLock")
- private void makeA2dpDeviceUnavailableNow(String address, int codec) {
+ private void makeA2dpDeviceUnavailableNow(String address, int codec, boolean deviceSwitch) {
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "a2dp." + address)
.set(MediaMetrics.Property.ENCODING, AudioSystem.audioFormatToString(codec))
.set(MediaMetrics.Property.EVENT, "makeA2dpDeviceUnavailableNow");
@@ -2392,7 +2402,7 @@ public class AudioDeviceInventory {
AudioDeviceAttributes ada = new AudioDeviceAttributes(
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
final int res = mAudioSystem.setDeviceConnectionState(ada,
- AudioSystem.DEVICE_STATE_UNAVAILABLE, codec);
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, codec, deviceSwitch);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
@@ -2403,7 +2413,8 @@ public class AudioDeviceInventory {
} else {
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
"A2DP device addr=" + Utils.anonymizeBluetoothAddress(address)
- + " made unavailable")).printSlog(EventLogger.Event.ALOGI, TAG));
+ + " made unavailable, deviceSwitch" + deviceSwitch))
+ .printSlog(EventLogger.Event.ALOGI, TAG));
}
mApmConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
@@ -2439,7 +2450,7 @@ public class AudioDeviceInventory {
final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
AudioSystem.DEVICE_STATE_AVAILABLE,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioSystem.AUDIO_FORMAT_DEFAULT, false);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"APM failed to make available A2DP source device addr="
@@ -2464,7 +2475,7 @@ public class AudioDeviceInventory {
AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioSystem.AUDIO_FORMAT_DEFAULT, false);
// always remove regardless of the result
mConnectedDevices.remove(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
@@ -2484,7 +2495,7 @@ public class AudioDeviceInventory {
DEVICE_OUT_HEARING_AID, address, name);
final int res = mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_AVAILABLE,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioSystem.AUDIO_FORMAT_DEFAULT, false);
if (asDeviceConnectionFailure() && res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueueAndSlog(
"APM failed to make available HearingAid addr=" + address
@@ -2514,12 +2525,12 @@ public class AudioDeviceInventory {
}
@GuardedBy("mDevicesLock")
- private void makeHearingAidDeviceUnavailable(String address) {
+ private void makeHearingAidDeviceUnavailable(String address, boolean deviceSwitch) {
AudioDeviceAttributes ada = new AudioDeviceAttributes(
DEVICE_OUT_HEARING_AID, address);
mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioSystem.AUDIO_FORMAT_DEFAULT, deviceSwitch);
// always remove regardless of return code
mConnectedDevices.remove(
DeviceInfo.makeDeviceListKey(DEVICE_OUT_HEARING_AID, address));
@@ -2621,7 +2632,7 @@ public class AudioDeviceInventory {
AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name);
final int res = mAudioSystem.setDeviceConnectionState(ada,
- AudioSystem.DEVICE_STATE_AVAILABLE, codec);
+ AudioSystem.DEVICE_STATE_AVAILABLE, codec, false /*deviceSwitch*/);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueueAndSlog(
"APM failed to make available LE Audio device addr=" + address
@@ -2668,13 +2679,13 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeLeAudioDeviceUnavailableNow(String address, int device,
- @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) {
+ @AudioSystem.AudioFormatNativeEnumForBtCodec int codec, boolean deviceSwitch) {
AudioDeviceAttributes ada = null;
if (device != AudioSystem.DEVICE_NONE) {
ada = new AudioDeviceAttributes(device, address);
final int res = mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
- codec);
+ codec, deviceSwitch);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
@@ -2684,7 +2695,8 @@ public class AudioDeviceInventory {
} else {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"LE Audio device addr=" + Utils.anonymizeBluetoothAddress(address)
- + " made unavailable").printSlog(EventLogger.Event.ALOGI, TAG));
+ + " made unavailable, deviceSwitch" + deviceSwitch)
+ .printSlog(EventLogger.Event.ALOGI, TAG));
}
mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 86871ea45d13..813e661d6970 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -63,6 +63,7 @@ import static com.android.media.audio.Flags.audioserverPermissions;
import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume;
import static com.android.media.audio.Flags.deferWearPermissionUpdates;
import static com.android.media.audio.Flags.equalScoLeaVcIndexRange;
+import static com.android.media.audio.Flags.optimizeBtDeviceSwitch;
import static com.android.media.audio.Flags.replaceStreamBtSco;
import static com.android.media.audio.Flags.ringMyCar;
import static com.android.media.audio.Flags.ringerModeAffectsAlarm;
@@ -585,6 +586,9 @@ public class AudioService extends IAudioService.Stub
// protects mRingerMode
private final Object mSettingsLock = new Object();
+ // protects VolumeStreamState / VolumeGroupState operations
+ private final Object mVolumeStateLock = new Object();
+
/** Maximum volume index values for audio streams */
protected static int[] MAX_STREAM_VOLUME = new int[] {
5, // STREAM_VOICE_CALL
@@ -1611,7 +1615,7 @@ public class AudioService extends IAudioService.Stub
private void initVolumeStreamStates() {
int numStreamTypes = AudioSystem.getNumStreamTypes();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
final VolumeStreamState streamState = getVssForStream(streamType);
if (streamState == null) {
@@ -2419,7 +2423,7 @@ public class AudioService extends IAudioService.Stub
private void checkAllAliasStreamVolumes() {
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
int streamAlias = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1);
@@ -2501,7 +2505,7 @@ public class AudioService extends IAudioService.Stub
private void onUpdateVolumeStatesForAudioDevice(int device, String caller) {
final int numStreamTypes = AudioSystem.getNumStreamTypes();
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
updateVolumeStates(device, streamType, caller);
}
@@ -2770,7 +2774,7 @@ public class AudioService extends IAudioService.Stub
updateDefaultVolumes();
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
getVssForStreamOrDefault(AudioSystem.STREAM_DTMF)
.setAllIndexes(getVssForStreamOrDefault(dtmfStreamAlias), caller);
getVssForStreamOrDefault(AudioSystem.STREAM_ACCESSIBILITY).setSettingName(
@@ -3232,8 +3236,10 @@ public class AudioService extends IAudioService.Stub
// Each stream will read its own persisted settings
// Broadcast the sticky intents
- broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
- broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
+ synchronized (mSettingsLock) {
+ broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
+ broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
+ }
// Broadcast vibrate settings
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
@@ -4235,7 +4241,7 @@ public class AudioService extends IAudioService.Stub
private void muteAliasStreams(int streamAlias, boolean state) {
// Locking mSettingsLock to avoid inversion when calling doMute -> updateVolumeGroupIndex
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
List<Integer> streamsToMute = new ArrayList<>();
for (int streamIdx = 0; streamIdx < mStreamStates.size(); streamIdx++) {
final VolumeStreamState vss = mStreamStates.valueAt(streamIdx);
@@ -4279,7 +4285,7 @@ public class AudioService extends IAudioService.Stub
// Locking mSettingsLock to avoid inversion when calling vss.mute -> vss.doMute ->
// vss.updateVolumeGroupIndex
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
final VolumeStreamState streamState = getVssForStreamOrDefault(streamAlias);
// if unmuting causes a change, it was muted
wasMuted = streamState.mute(false, "onUnmuteStreamOnSingleVolDevice");
@@ -4455,7 +4461,7 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#getVolumeGroupVolumeIndex(int) */
public int getVolumeGroupVolumeIndex(int groupId) {
super.getVolumeGroupVolumeIndex_enforcePermission();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, "No volume group for id " + groupId);
return 0;
@@ -4472,7 +4478,7 @@ public class AudioService extends IAudioService.Stub
MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING })
public int getVolumeGroupMaxVolumeIndex(int groupId) {
super.getVolumeGroupMaxVolumeIndex_enforcePermission();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, "No volume group for id " + groupId);
return 0;
@@ -4487,7 +4493,7 @@ public class AudioService extends IAudioService.Stub
MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING })
public int getVolumeGroupMinVolumeIndex(int groupId) {
super.getVolumeGroupMinVolumeIndex_enforcePermission();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, "No volume group for id " + groupId);
return 0;
@@ -4632,7 +4638,7 @@ public class AudioService extends IAudioService.Stub
@android.annotation.EnforcePermission(QUERY_AUDIO_STATE)
public int getLastAudibleVolumeForVolumeGroup(int groupId) {
super.getLastAudibleVolumeForVolumeGroup_enforcePermission();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, ": no volume group found for id " + groupId);
return 0;
@@ -4644,7 +4650,7 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#isVolumeGroupMuted(int) */
public boolean isVolumeGroupMuted(int groupId) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
Log.e(TAG, ": no volume group found for id " + groupId);
return false;
@@ -4990,6 +4996,8 @@ public class AudioService extends IAudioService.Stub
+ cacheGetStreamMinMaxVolume());
pw.println("\tandroid.media.audio.Flags.cacheGetStreamVolume:"
+ cacheGetStreamVolume());
+ pw.println("\tcom.android.media.audio.optimizeBtDeviceSwitch:"
+ + optimizeBtDeviceSwitch());
}
private void dumpAudioMode(PrintWriter pw) {
@@ -5470,7 +5478,7 @@ public class AudioService extends IAudioService.Stub
}
streamType = replaceBtScoStreamWithVoiceCall(streamType, "isStreamMute");
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
ensureValidStreamType(streamType);
return getVssForStreamOrDefault(streamType).mIsMuted;
}
@@ -5651,7 +5659,7 @@ public class AudioService extends IAudioService.Stub
}
private int getStreamVolume(int streamType, int device) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
final VolumeStreamState vss = getVssForStreamOrDefault(streamType);
int index = vss.getIndex(device);
@@ -5695,7 +5703,7 @@ public class AudioService extends IAudioService.Stub
vib.setMinVolumeIndex((vss.mIndexMin + 5) / 10);
vib.setMaxVolumeIndex((vss.mIndexMax + 5) / 10);
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
final int index;
if (isFixedVolumeDevice(ada.getInternalType())) {
index = (vss.mIndexMax + 5) / 10;
@@ -6263,7 +6271,7 @@ public class AudioService extends IAudioService.Stub
// ring and notifications volume should never be 0 when not silenced
if (sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_RING
|| sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_NOTIFICATION) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int i = 0; i < vss.mIndexMap.size(); i++) {
int device = vss.mIndexMap.keyAt(i);
int value = vss.mIndexMap.valueAt(i);
@@ -7023,7 +7031,7 @@ public class AudioService extends IAudioService.Stub
}
streamState.readSettings();
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// unmute stream that was muted but is not affect by mute anymore
if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
!isStreamMutedByRingerOrZenMode(streamType)) || mUseFixedVolume)) {
@@ -8056,14 +8064,14 @@ public class AudioService extends IAudioService.Stub
public Set<Integer> getDeviceSetForStream(int stream) {
stream = replaceBtScoStreamWithVoiceCall(stream, "getDeviceSetForStream");
ensureValidStreamType(stream);
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
return getVssForStreamOrDefault(stream).observeDevicesForStream_syncVSS(true);
}
}
private void onObserveDevicesForAllStreams(int skipStream) {
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int stream = 0; stream < mStreamStates.size(); stream++) {
final VolumeStreamState vss = mStreamStates.valueAt(stream);
if (vss != null && vss.getStreamType() != skipStream) {
@@ -8645,7 +8653,7 @@ public class AudioService extends IAudioService.Stub
private void readVolumeGroupsSettings(boolean userSwitch) {
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (DEBUG_VOL) {
Log.d(TAG, "readVolumeGroupsSettings userSwitch=" + userSwitch);
}
@@ -8703,7 +8711,7 @@ public class AudioService extends IAudioService.Stub
// NOTE: Locking order for synchronized objects related to volume management:
// 1 mSettingsLock
- // 2 VolumeStreamState.class
+ // 2 mVolumeStateLock
private class VolumeGroupState {
private final AudioVolumeGroup mAudioVolumeGroup;
private final SparseIntArray mIndexMap = new SparseIntArray(8);
@@ -8797,7 +8805,7 @@ public class AudioService extends IAudioService.Stub
* Mute/unmute the volume group
* @param muted the new mute state
*/
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
public boolean mute(boolean muted) {
if (!isMutable()) {
// Non mutable volume group
@@ -8821,7 +8829,7 @@ public class AudioService extends IAudioService.Stub
public void adjustVolume(int direction, int flags) {
synchronized (mSettingsLock) {
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
int device = getDeviceForVolume();
int previousIndex = getIndex(device);
if (isMuteAdjust(direction) && !isMutable()) {
@@ -8875,14 +8883,14 @@ public class AudioService extends IAudioService.Stub
}
public int getVolumeIndex() {
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
return getIndex(getDeviceForVolume());
}
}
public void setVolumeIndex(int index, int flags) {
synchronized (mSettingsLock) {
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (mUseFixedVolume) {
return;
}
@@ -8891,7 +8899,7 @@ public class AudioService extends IAudioService.Stub
}
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private void setVolumeIndex(int index, int device, int flags) {
// Update cache & persist (muted by volume 0 shall be persisted)
updateVolumeIndex(index, device);
@@ -8904,7 +8912,7 @@ public class AudioService extends IAudioService.Stub
}
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
public void updateVolumeIndex(int index, int device) {
// Filter persistency if already exist and the index has not changed
if (mIndexMap.indexOfKey(device) < 0 || mIndexMap.get(device) != index) {
@@ -8922,7 +8930,7 @@ public class AudioService extends IAudioService.Stub
}
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private void setVolumeIndexInt(int index, int device, int flags) {
// Reflect mute state of corresponding stream by forcing index to 0 if muted
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
@@ -8955,14 +8963,14 @@ public class AudioService extends IAudioService.Stub
mAudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, muted, device);
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private int getIndex(int device) {
int index = mIndexMap.get(device, -1);
// there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
return (index != -1) ? index : mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private boolean hasIndexForDevice(int device) {
return (mIndexMap.get(device, -1) != -1);
}
@@ -8989,7 +8997,7 @@ public class AudioService extends IAudioService.Stub
public void applyAllVolumes(boolean userSwitch) {
String caller = "from vgs";
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// apply device specific volumes first
for (int i = 0; i < mIndexMap.size(); i++) {
int device = mIndexMap.keyAt(i);
@@ -9092,25 +9100,27 @@ public class AudioService extends IAudioService.Stub
if (mUseFixedVolume || mHasValidStreamType) {
return;
}
- if (DEBUG_VOL) {
- Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group "
- + mAudioVolumeGroup.name()
- + ", device " + AudioSystem.getOutputDeviceName(device)
- + " and User=" + getCurrentUserId()
- + " mSettingName: " + mSettingName);
- }
+ synchronized (mVolumeStateLock) {
+ if (DEBUG_VOL) {
+ Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device)
+ + " for group " + mAudioVolumeGroup.name()
+ + ", device " + AudioSystem.getOutputDeviceName(device)
+ + " and User=" + getCurrentUserId()
+ + " mSettingName: " + mSettingName);
+ }
- boolean success = mSettings.putSystemIntForUser(mContentResolver,
- getSettingNameForDevice(device),
- getIndex(device),
- getVolumePersistenceUserId());
- if (!success) {
- Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name());
+ boolean success = mSettings.putSystemIntForUser(mContentResolver,
+ getSettingNameForDevice(device),
+ getIndex(device),
+ getVolumePersistenceUserId());
+ if (!success) {
+ Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name());
+ }
}
}
public void readSettings() {
- synchronized (AudioService.VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// force maximum volume on all streams if fixed volume property is set
if (mUseFixedVolume) {
mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
@@ -9144,7 +9154,7 @@ public class AudioService extends IAudioService.Stub
}
}
- @GuardedBy("AudioService.VolumeStreamState.class")
+ @GuardedBy("AudioService.this.mVolumeStateLock")
private int getValidIndex(int index) {
if (index < mIndexMin) {
return mIndexMin;
@@ -9218,7 +9228,7 @@ public class AudioService extends IAudioService.Stub
// 1 mScoclient OR mSafeMediaVolumeState
// 2 mSetModeLock
// 3 mSettingsLock
- // 4 VolumeStreamState.class
+ // 4 mVolumeStateLock
/*package*/ class VolumeStreamState {
private final int mStreamType;
private VolumeGroupState mVolumeGroupState = null;
@@ -9427,7 +9437,7 @@ public class AudioService extends IAudioService.Stub
*
* This is a reference to the local list, do not modify.
*/
- @GuardedBy("VolumeStreamState.class")
+ @GuardedBy("mVolumeStateLock")
@NonNull
public Set<Integer> observeDevicesForStream_syncVSS(
boolean checkOthers) {
@@ -9495,7 +9505,7 @@ public class AudioService extends IAudioService.Stub
public void readSettings() {
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// force maximum volume on all streams if fixed volume property is set
if (mUseFixedVolume) {
mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
@@ -9515,7 +9525,7 @@ public class AudioService extends IAudioService.Stub
}
}
}
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {
// retrieve current volume for device
@@ -9548,7 +9558,7 @@ public class AudioService extends IAudioService.Stub
* will send the non-zero index together with muted state. Otherwise, index 0 will be sent
* to native for signalising a muted stream.
**/
- @GuardedBy("VolumeStreamState.class")
+ @GuardedBy("mVolumeStateLock")
private void setStreamVolumeIndex(int index, int device) {
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
// This allows RX path muting by the audio HAL only when explicitly muted but not when
@@ -9570,8 +9580,8 @@ public class AudioService extends IAudioService.Stub
mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, muted, device);
}
- // must be called while synchronized VolumeStreamState.class
- @GuardedBy("VolumeStreamState.class")
+ // must be called while synchronized mVolumeStateLock
+ @GuardedBy("mVolumeStateLock")
/*package*/ void applyDeviceVolume_syncVSS(int device) {
int index;
if (isFullyMuted() && !ringMyCar()) {
@@ -9597,7 +9607,7 @@ public class AudioService extends IAudioService.Stub
}
public void applyAllVolumes() {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// apply device specific volumes first
int index;
boolean isAbsoluteVolume = false;
@@ -9659,7 +9669,7 @@ public class AudioService extends IAudioService.Stub
final boolean isCurrentDevice;
final StringBuilder aliasStreamIndexes = new StringBuilder();
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
oldIndex = getIndex(device);
index = getValidIndex(index, hasModifyAudioSettings);
// for STREAM_SYSTEM_ENFORCED, do not sync aliased streams on the enforced index
@@ -9777,7 +9787,7 @@ public class AudioService extends IAudioService.Stub
}
public int getIndex(int device) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
int index = mIndexMap.get(device, -1);
if (index == -1) {
// there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
@@ -9788,7 +9798,7 @@ public class AudioService extends IAudioService.Stub
}
public @NonNull VolumeInfo getVolumeInfo(int device) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
int index = mIndexMap.get(device, -1);
if (index == -1) {
// there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
@@ -9805,7 +9815,7 @@ public class AudioService extends IAudioService.Stub
}
public boolean hasIndexForDevice(int device) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
return (mIndexMap.get(device, -1) != -1);
}
}
@@ -9837,8 +9847,8 @@ public class AudioService extends IAudioService.Stub
* @param srcStream
* @param caller
*/
- // must be sync'd on mSettingsLock before VolumeStreamState.class
- @GuardedBy("VolumeStreamState.class")
+ // must be sync'd on mSettingsLock before mVolumeStateLock
+ @GuardedBy("mVolumeStateLock")
public void setAllIndexes(VolumeStreamState srcStream, String caller) {
if (srcStream == null || mStreamType == srcStream.mStreamType) {
return;
@@ -9862,8 +9872,8 @@ public class AudioService extends IAudioService.Stub
}
}
- // must be sync'd on mSettingsLock before VolumeStreamState.class
- @GuardedBy("VolumeStreamState.class")
+ // must be sync'd on mSettingsLock before mVolumeStateLock
+ @GuardedBy("mVolumeStateLock")
public void setAllIndexesToMax() {
for (int i = 0; i < mIndexMap.size(); i++) {
mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
@@ -9876,7 +9886,7 @@ public class AudioService extends IAudioService.Stub
// vss.setIndex which grabs this lock after VSS.class. Locking order needs to be
// preserved
synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (mVolumeGroupState != null) {
int groupIndex = (getIndex(device) + 5) / 10;
if (DEBUG_VOL) {
@@ -9908,7 +9918,7 @@ public class AudioService extends IAudioService.Stub
*/
public boolean mute(boolean state, String source) {
boolean changed = false;
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
changed = mute(state, true, source);
}
if (changed) {
@@ -9924,7 +9934,7 @@ public class AudioService extends IAudioService.Stub
*/
public boolean muteInternally(boolean state) {
boolean changed = false;
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
if (state != mIsMutedInternally) {
changed = true;
mIsMutedInternally = state;
@@ -9939,7 +9949,7 @@ public class AudioService extends IAudioService.Stub
return changed;
}
- @GuardedBy("VolumeStreamState.class")
+ @GuardedBy("mVolumeStateLock")
public boolean isFullyMuted() {
return mIsMuted || mIsMutedInternally;
}
@@ -9960,7 +9970,7 @@ public class AudioService extends IAudioService.Stub
*/
public boolean mute(boolean state, boolean apply, String src) {
boolean changed;
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
changed = state != mIsMuted;
if (changed) {
sMuteLogger.enqueue(
@@ -9994,7 +10004,7 @@ public class AudioService extends IAudioService.Stub
}
public void doMute() {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// If associated to volume group, update group cache
updateVolumeGroupIndex(getDeviceForStream(mStreamType), /* forceMuteState= */true);
@@ -10015,7 +10025,7 @@ public class AudioService extends IAudioService.Stub
}
public void checkFixedVolumeDevices() {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
// ignore settings for fixed volume devices: volume should always be at max or 0
if (sStreamVolumeAlias.get(mStreamType) == AudioSystem.STREAM_MUSIC) {
for (int i = 0; i < mIndexMap.size(); i++) {
@@ -10186,8 +10196,7 @@ public class AudioService extends IAudioService.Stub
}
/*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) {
-
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
sendMsg(mAudioHandler, SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION, SENDMSG_QUEUE,
device, (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device)
|| AudioSystem.isLeAudioDeviceType(device) ? 1 : 0),
@@ -12191,7 +12200,7 @@ public class AudioService extends IAudioService.Stub
mCameraSoundForced = cameraSoundForced;
if (cameraSoundForcedChanged) {
if (!mIsSingleVolume) {
- synchronized (VolumeStreamState.class) {
+ synchronized (mVolumeStateLock) {
final VolumeStreamState s = getVssForStreamOrDefault(
AudioSystem.STREAM_SYSTEM_ENFORCED);
if (cameraSoundForced) {
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index e86c34cab88a..a6267c156fb3 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -367,9 +367,9 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback,
* @return
*/
public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
- int codecFormat) {
+ int codecFormat, boolean deviceSwitch) {
invalidateRoutingCache();
- return AudioSystem.setDeviceConnectionState(attributes, state, codecFormat);
+ return AudioSystem.setDeviceConnectionState(attributes, state, codecFormat, deviceSwitch);
}
/**
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 0479c70656b7..844e3524384d 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -26,6 +26,8 @@ import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER;
import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN;
import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_WATCH;
+import static com.android.media.audio.Flags.optimizeBtDeviceSwitch;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothA2dp;
@@ -393,8 +395,11 @@ public class BtHelper {
+ "received with null profile proxy for device: "
+ btDevice)).printLog(TAG));
return;
+
}
- onSetBtScoActiveDevice(btDevice);
+ boolean deviceSwitch = optimizeBtDeviceSwitch()
+ && btDevice != null && mBluetoothHeadsetDevice != null;
+ onSetBtScoActiveDevice(btDevice, deviceSwitch);
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
onScoAudioStateChanged(btState);
@@ -814,7 +819,7 @@ public class BtHelper {
if (device == null) {
continue;
}
- onSetBtScoActiveDevice(device);
+ onSetBtScoActiveDevice(device, false /*deviceSwitch*/);
}
} else {
Log.e(TAG, "onHeadsetProfileConnected: Null BluetoothAdapter");
@@ -907,7 +912,8 @@ public class BtHelper {
}
@GuardedBy("mDeviceBroker.mDeviceStateLock")
- private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
+ private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive,
+ boolean deviceSwitch) {
if (btDevice == null) {
return true;
}
@@ -919,12 +925,12 @@ public class BtHelper {
if (isActive) {
audioDevice = btHeadsetDeviceToAudioDevice(btDevice);
result = mDeviceBroker.handleDeviceConnection(
- audioDevice, true /*connect*/, btDevice);
+ audioDevice, true /*connect*/, btDevice, false /*deviceSwitch*/);
} else {
AudioDeviceAttributes ada = mResolvedScoAudioDevices.get(btDevice);
if (ada != null) {
result = mDeviceBroker.handleDeviceConnection(
- ada, false /*connect*/, btDevice);
+ ada, false /*connect*/, btDevice, deviceSwitch);
} else {
// Disconnect all possible audio device types if the disconnected device type is
// unknown
@@ -935,7 +941,8 @@ public class BtHelper {
};
for (int outDeviceType : outDeviceTypes) {
result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
- outDeviceType, address, name), false /*connect*/, btDevice);
+ outDeviceType, address, name), false /*connect*/, btDevice,
+ deviceSwitch);
}
}
}
@@ -944,7 +951,7 @@ public class BtHelper {
// handleDeviceConnection() && result to make sure the method get executed
result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
inDevice, address, name),
- isActive, btDevice) && result;
+ isActive, btDevice, deviceSwitch) && result;
if (result) {
if (isActive) {
mResolvedScoAudioDevices.put(btDevice, audioDevice);
@@ -961,18 +968,18 @@ public class BtHelper {
}
@GuardedBy("mDeviceBroker.mDeviceStateLock")
- /*package */ void onSetBtScoActiveDevice(BluetoothDevice btDevice) {
+ /*package */ void onSetBtScoActiveDevice(BluetoothDevice btDevice, boolean deviceSwitch) {
Log.i(TAG, "onSetBtScoActiveDevice: " + getAnonymizedAddress(mBluetoothHeadsetDevice)
- + " -> " + getAnonymizedAddress(btDevice));
+ + " -> " + getAnonymizedAddress(btDevice) + ", deviceSwitch: " + deviceSwitch);
final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
if (Objects.equals(btDevice, previousActiveDevice)) {
return;
}
- if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
+ if (!handleBtScoActiveDeviceChange(previousActiveDevice, false, deviceSwitch)) {
Log.w(TAG, "onSetBtScoActiveDevice() failed to remove previous device "
+ getAnonymizedAddress(previousActiveDevice));
}
- if (!handleBtScoActiveDeviceChange(btDevice, true)) {
+ if (!handleBtScoActiveDeviceChange(btDevice, true, false /*deviceSwitch*/)) {
Log.e(TAG, "onSetBtScoActiveDevice() failed to add new device "
+ getAnonymizedAddress(btDevice));
// set mBluetoothHeadsetDevice to null when failing to add new device
@@ -1291,6 +1298,29 @@ public class BtHelper {
return 0; // 0 is not a valid profile
}
+ /*package */ static int getTypeFromProfile(int profile, boolean isLeOutput) {
+ switch (profile) {
+ case BluetoothProfile.A2DP_SINK:
+ return AudioSystem.DEVICE_IN_BLUETOOTH_A2DP;
+ case BluetoothProfile.A2DP:
+ return AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
+ case BluetoothProfile.HEARING_AID:
+ return AudioSystem.DEVICE_OUT_HEARING_AID;
+ case BluetoothProfile.LE_AUDIO:
+ if (isLeOutput) {
+ return AudioSystem.DEVICE_OUT_BLE_HEADSET;
+ } else {
+ return AudioSystem.DEVICE_IN_BLE_HEADSET;
+ }
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ return AudioSystem.DEVICE_OUT_BLE_BROADCAST;
+ case BluetoothProfile.HEADSET:
+ return AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
+ default:
+ throw new IllegalArgumentException("Invalid profile " + profile);
+ }
+ }
+
/*package */ static Bundle getPreferredAudioProfiles(String address) {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
return adapter.getPreferredAudioProfiles(adapter.getRemoteDevice(address));
diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
index b11267ef8634..79523bd02404 100644
--- a/services/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -69,6 +69,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
private static final String SYSTEM_GENDER_HELPER = "system_gender";
private static final String DISPLAY_HELPER = "display";
private static final String INPUT_HELPER = "input";
+ private static final String WEAR_BACKUP_HELPER = "wear";
// These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME
// are also used in the full-backup file format, so must not change unless steps are
@@ -113,7 +114,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
private static final Set<String> sEligibleHelpersForNonSystemUser =
SetUtils.union(sEligibleHelpersForProfileUser,
Sets.newArraySet(ACCOUNT_MANAGER_HELPER, USAGE_STATS_HELPER, PREFERRED_HELPER,
- SHORTCUT_MANAGER_HELPER, INPUT_HELPER));
+ SHORTCUT_MANAGER_HELPER, INPUT_HELPER, WEAR_BACKUP_HELPER));
private int mUserId = UserHandle.USER_SYSTEM;
private boolean mIsProfileUser = false;
@@ -153,6 +154,11 @@ public class SystemBackupAgent extends BackupAgentHelper {
if (com.android.hardware.input.Flags.enableBackupAndRestoreForInputGestures()) {
addHelperIfEligibleForUser(INPUT_HELPER, new InputBackupHelper(mUserId));
}
+
+ // Add Wear helper only if the device is a watch
+ if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ addHelperIfEligibleForUser(WEAR_BACKUP_HELPER, new WearBackupHelper());
+ }
}
@Override
diff --git a/services/core/java/com/android/server/backup/WearBackupHelper.java b/services/core/java/com/android/server/backup/WearBackupHelper.java
new file mode 100644
index 000000000000..27416b3eb2a6
--- /dev/null
+++ b/services/core/java/com/android/server/backup/WearBackupHelper.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://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.backup;
+
+import android.annotation.Nullable;
+import android.app.backup.BlobBackupHelper;
+
+import com.android.server.LocalServices;
+
+/** A {@link android.app.backup.BlobBackupHelper} for Wear */
+public class WearBackupHelper extends BlobBackupHelper {
+
+ private static final int BLOB_VERSION = 1;
+ private static final String KEY_WEAR_BACKUP = "wear";
+ @Nullable private final WearBackupInternal mWearBackupInternal;
+
+ public WearBackupHelper() {
+ super(BLOB_VERSION, KEY_WEAR_BACKUP);
+ mWearBackupInternal = LocalServices.getService(WearBackupInternal.class);
+ }
+
+ @Override
+ protected byte[] getBackupPayload(String key) {
+ return KEY_WEAR_BACKUP.equals(key) && mWearBackupInternal != null
+ ? mWearBackupInternal.getBackupPayload(getLogger())
+ : null;
+ }
+
+ @Override
+ protected void applyRestoredPayload(String key, byte[] payload) {
+ if (KEY_WEAR_BACKUP.equals(key) && mWearBackupInternal != null) {
+ mWearBackupInternal.applyRestoredPayload(payload);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/backup/WearBackupInternal.java b/services/core/java/com/android/server/backup/WearBackupInternal.java
new file mode 100644
index 000000000000..7b4847b51df6
--- /dev/null
+++ b/services/core/java/com/android/server/backup/WearBackupInternal.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://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.backup;
+
+import android.app.backup.BackupRestoreEventLogger;
+
+import com.android.internal.annotations.Keep;
+
+/** A local service internal for Wear OS handle backup/restore */
+@Keep
+public interface WearBackupInternal {
+
+ /** Gets the backup payload */
+ byte[] getBackupPayload(BackupRestoreEventLogger logger);
+
+ /** Applies the restored payload */
+ void applyRestoredPayload(byte[] payload);
+}
diff --git a/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java
index 000ee5446962..9f364677705e 100644
--- a/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java
+++ b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java
@@ -20,12 +20,16 @@ import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
import android.annotation.NonNull;
import android.hardware.SensorPrivacyManager;
+import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraManager;
+import android.util.Log;
import java.util.concurrent.ConcurrentHashMap;
public class BiometricCameraManagerImpl implements BiometricCameraManager {
+ private static final String TAG = "BiometricCameraManager";
+
private final CameraManager mCameraManager;
private final SensorPrivacyManager mSensorPrivacyManager;
private final ConcurrentHashMap<String, Boolean> mIsCameraAvailable = new ConcurrentHashMap<>();
@@ -52,12 +56,18 @@ public class BiometricCameraManagerImpl implements BiometricCameraManager {
@Override
public boolean isAnyCameraUnavailable() {
- for (String cameraId : mIsCameraAvailable.keySet()) {
- if (!mIsCameraAvailable.get(cameraId)) {
- return true;
+ try {
+ for (String cameraId : mCameraManager.getCameraIdList()) {
+ if (!mIsCameraAvailable.getOrDefault(cameraId, true)) {
+ return true;
+ }
}
+ return false;
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Camera exception thrown when trying to determine availability: ", e);
+ //If face HAL is unable to get access to a camera, it will return an error.
+ return false;
}
- return false;
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 2bdb5c25d0d5..a749a4013cdc 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -68,6 +68,8 @@ abstract class DisplayDevice {
private int mCurrentLayerStack = -1;
private int mCurrentFlags = 0;
private int mCurrentOrientation = -1;
+ private int mLastDisplayWidth;
+ private int mLastDisplayHeight;
private Rect mCurrentLayerStackRect;
private Rect mCurrentDisplayRect;
private final Context mContext;
@@ -216,9 +218,9 @@ abstract class DisplayDevice {
}
/**
- * Gives the display device a chance to update its properties while in a transaction.
+ * Updates the surface for the display.
*/
- public void performTraversalLocked(SurfaceControl.Transaction t) {
+ public void configureSurfaceLocked(SurfaceControl.Transaction t) {
}
/**
@@ -374,6 +376,29 @@ abstract class DisplayDevice {
}
/**
+ * Configure transaction with the display size.
+ */
+ public void configureDisplaySizeLocked(SurfaceControl.Transaction t) {
+ DisplayDeviceInfo info = getDisplayDeviceInfoLocked();
+ boolean isInstalledRotated = info.installOrientation == ROTATION_90
+ || info.installOrientation == ROTATION_270;
+ int displayWidth = isInstalledRotated ? info.height : info.width;
+ int displayHeight = isInstalledRotated ? info.width : info.height;
+ setDisplaySizeLocked(t, displayWidth, displayHeight);
+ }
+
+ /**
+ * Sets display size while in a transaction.
+ */
+ public final void setDisplaySizeLocked(SurfaceControl.Transaction t, int width, int height) {
+ if (width != mLastDisplayWidth && height != mLastDisplayHeight) {
+ mLastDisplayWidth = width;
+ mLastDisplayHeight = height;
+ t.setDisplaySize(mDisplayToken, width, height);
+ }
+ }
+
+ /**
* Sets the display surface while in a transaction.
*/
public final void setSurfaceLocked(SurfaceControl.Transaction t, Surface surface) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 854b0dd7676b..d4bb1d52c111 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2587,6 +2587,11 @@ public final class DisplayManagerService extends SystemService {
sendDisplayEventIfEnabledLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED);
}
+ private void handleLogicalDisplayCommittedStateChangedLocked(@NonNull LogicalDisplay display) {
+ sendDisplayEventIfEnabledLocked(display,
+ DisplayManagerGlobal.EVENT_DISPLAY_COMMITTED_STATE_CHANGED);
+ }
+
private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) {
mDisplayModeDirector.defaultDisplayDeviceUpdated(display.getPrimaryDisplayDeviceLocked()
.mDisplayDeviceConfig);
@@ -2609,7 +2614,8 @@ public final class DisplayManagerService extends SystemService {
// Blank or unblank the display immediately to match the state requested
// by the display power controller (if known).
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
- if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
+ if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0
+ || android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display == null) {
return null;
@@ -3122,7 +3128,6 @@ public final class DisplayManagerService extends SystemService {
displayTransactions.get(display.getDisplayIdLocked(), t);
if (device != null) {
configureDisplayLocked(displayTransaction, device);
- device.performTraversalLocked(displayTransaction);
}
});
@@ -4166,6 +4171,9 @@ public final class DisplayManagerService extends SystemService {
case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_STATE_CHANGED:
handleLogicalDisplayStateChangedLocked(display);
break;
+ case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED:
+ handleLogicalDisplayCommittedStateChangedLocked(display);
+ break;
}
}
@@ -4420,6 +4428,9 @@ public final class DisplayManagerService extends SystemService {
case DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED:
return (mask & DisplayManagerGlobal
.INTERNAL_EVENT_FLAG_DISPLAY_STATE) != 0;
+ case DisplayManagerGlobal.EVENT_DISPLAY_COMMITTED_STATE_CHANGED:
+ return (mask & DisplayManagerGlobal
+ .INTERNAL_EVENT_FLAG_DISPLAY_COMMITTED_STATE_CHANGED) != 0;
default:
// This should never happen.
Slog.e(TAG, "Unknown display event " + event);
@@ -5564,7 +5575,9 @@ public final class DisplayManagerService extends SystemService {
final DisplayDevice displayDevice = mLogicalDisplayMapper.getDisplayLocked(
id).getPrimaryDisplayDeviceLocked();
final int flags = displayDevice.getDisplayDeviceInfoLocked().flags;
- if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
+ if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0
+ || android.companion.virtualdevice.flags.Flags
+ .correctVirtualDisplayPowerState()) {
final DisplayPowerController displayPowerController =
mDisplayPowerControllers.get(id);
if (displayPowerController != null) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 83ca563e0534..324f95a5974b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -35,6 +35,7 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.Trace;
+import android.util.DisplayMetrics;
import android.util.DisplayUtils;
import android.util.LongSparseArray;
import android.util.Slog;
@@ -84,6 +85,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.boot.emulator.circular";
private static final double DEFAULT_DISPLAY_SIZE = 24.0;
+ // Touch target size 10.4mm in inches (divided by mm per inch 25.4)
+ private static final double EXTERNAL_DISPLAY_BASE_TOUCH_TARGET_SIZE_IN_INCHES = 10.4 / 25.4;
+
+ private static final double BASE_TOUCH_TARGET_SIZE_DP = 48.0;
private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>();
@@ -530,17 +535,20 @@ final class LocalDisplayAdapter extends DisplayAdapter {
if (densityMapping == null) {
if (getFeatureFlags().isBaseDensityForExternalDisplaysEnabled()
&& !mStaticDisplayInfo.isInternal) {
- double dpi;
+ double ppi;
if (mActiveSfDisplayMode.xDpi > 0 && mActiveSfDisplayMode.yDpi > 0) {
- dpi = Math.sqrt((Math.pow(mActiveSfDisplayMode.xDpi, 2)
+ ppi = Math.sqrt((Math.pow(mActiveSfDisplayMode.xDpi, 2)
+ Math.pow(mActiveSfDisplayMode.yDpi, 2)) / 2);
} else {
// xDPI and yDPI is missing, calculate DPI from display resolution and
// default display size
- dpi = Math.sqrt(Math.pow(mInfo.width, 2) + Math.pow(mInfo.height, 2))
+ ppi = Math.sqrt(Math.pow(mInfo.width, 2) + Math.pow(mInfo.height, 2))
/ DEFAULT_DISPLAY_SIZE;
}
+ double pixels = ppi * EXTERNAL_DISPLAY_BASE_TOUCH_TARGET_SIZE_IN_INCHES;
+ double dpi =
+ pixels * DisplayMetrics.DENSITY_DEFAULT / BASE_TOUCH_TARGET_SIZE_DP;
return (int) (dpi + 0.5);
}
return (int) (mStaticDisplayInfo.density * 160 + 0.5);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index f9d413732e3e..b2b9ef17ec8d 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -228,14 +228,17 @@ final class LogicalDisplay {
*/
private final boolean mIsAnisotropyCorrectionEnabled;
+ private final boolean mSyncedResolutionSwitchEnabled;
+
private boolean mCanHostTasks;
LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
- this(displayId, layerStack, primaryDisplayDevice, false, false);
+ this(displayId, layerStack, primaryDisplayDevice, false, false, false);
}
LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice,
- boolean isAnisotropyCorrectionEnabled, boolean isAlwaysRotateDisplayDeviceEnabled) {
+ boolean isAnisotropyCorrectionEnabled, boolean isAlwaysRotateDisplayDeviceEnabled,
+ boolean isSyncedResolutionSwitchEnabled) {
mDisplayId = displayId;
mLayerStack = layerStack;
mPrimaryDisplayDevice = primaryDisplayDevice;
@@ -248,6 +251,7 @@ final class LogicalDisplay {
mBaseDisplayInfo.thermalBrightnessThrottlingDataId = mThermalBrightnessThrottlingDataId;
mIsAnisotropyCorrectionEnabled = isAnisotropyCorrectionEnabled;
mAlwaysRotateDisplayDeviceEnabled = isAlwaysRotateDisplayDeviceEnabled;
+ mSyncedResolutionSwitchEnabled = isSyncedResolutionSwitchEnabled;
mCanHostTasks = (mDisplayId == Display.DEFAULT_DISPLAY);
}
@@ -791,7 +795,12 @@ final class LogicalDisplay {
}
mDisplayPosition.set(mTempDisplayRect.left, mTempDisplayRect.top);
+
+ if (mSyncedResolutionSwitchEnabled || displayDeviceInfo.type == Display.TYPE_VIRTUAL) {
+ device.configureDisplaySizeLocked(t);
+ }
device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect);
+ device.configureSurfaceLocked(t);
}
/**
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index ecc8896b69c6..872f33484951 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -91,6 +91,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
public static final int LOGICAL_DISPLAY_EVENT_DISCONNECTED = 1 << 8;
public static final int LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED = 1 << 9;
public static final int LOGICAL_DISPLAY_EVENT_STATE_CHANGED = 1 << 10;
+ public static final int LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED = 1 << 11;
+
public static final int DISPLAY_GROUP_EVENT_ADDED = 1;
public static final int DISPLAY_GROUP_EVENT_CHANGED = 2;
@@ -810,7 +812,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
int logicalDisplayEventMask = mLogicalDisplaysToUpdate
.get(displayId, LOGICAL_DISPLAY_EVENT_BASE);
boolean hasBasicInfoChanged =
- !mTempDisplayInfo.equals(newDisplayInfo, /* compareRefreshRate */ false);
+ !mTempDisplayInfo.equals(newDisplayInfo, /* compareOnlyBasicChanges */ true);
// The display is no longer valid and needs to be removed.
if (!display.isValidLocked()) {
// Remove from group
@@ -930,6 +932,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_BASIC_CHANGED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_STATE_CHANGED);
+ sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CONNECTED);
@@ -961,6 +964,11 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
&& mTempDisplayInfo.state != newDisplayInfo.state) {
mask |= LOGICAL_DISPLAY_EVENT_STATE_CHANGED;
}
+
+ if (mFlags.isCommittedStateSeparateEventEnabled()
+ && mTempDisplayInfo.committedState != newDisplayInfo.committedState) {
+ mask |= LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED;
+ }
return mask;
}
/**
@@ -1248,7 +1256,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
final int layerStack = assignLayerStackLocked(displayId);
final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device,
mFlags.isPixelAnisotropyCorrectionInLogicalDisplayEnabled(),
- mFlags.isAlwaysRotateDisplayDeviceEnabled());
+ mFlags.isAlwaysRotateDisplayDeviceEnabled(),
+ mFlags.isSyncedResolutionSwitchEnabled());
display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager);
final DisplayInfo info = display.getDisplayInfoLocked();
@@ -1359,6 +1368,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
return "disconnected";
case LOGICAL_DISPLAY_EVENT_STATE_CHANGED:
return "state_changed";
+ case LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED:
+ return "committed_state_changed";
case LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED:
return "refresh_rate_changed";
case LOGICAL_DISPLAY_EVENT_BASIC_CHANGED:
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 382c88327523..b5a9b19bc5c5 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -341,7 +341,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
}
@Override
- public void performTraversalLocked(SurfaceControl.Transaction t) {
+ public void configureSurfaceLocked(SurfaceControl.Transaction t) {
if (mSurfaceTexture != null) {
if (mSurface == null) {
mSurface = new Surface(mSurfaceTexture);
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index abbdeb9da364..e7939bb50ece 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -371,7 +371,15 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mCallback = callback;
mProjection = projection;
mMediaProjectionCallback = mediaProjectionCallback;
- mDisplayState = Display.STATE_ON;
+ if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
+ // The display's power state depends on the power state of the state of its
+ // display / power group, which we don't know here. Initializing to UNKNOWN allows
+ // the first call to requestDisplayStateLocked() to set the correct state.
+ // This also triggers VirtualDisplay.Callback to tell the owner the initial state.
+ mDisplayState = Display.STATE_UNKNOWN;
+ } else {
+ mDisplayState = Display.STATE_ON;
+ }
mPendingChanges |= PENDING_SURFACE_CHANGE;
mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror();
mIsWindowManagerMirroring = virtualDisplayConfig.isWindowManagerMirroringEnabled();
@@ -484,14 +492,19 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
}
@Override
- public void performTraversalLocked(SurfaceControl.Transaction t) {
- if ((mPendingChanges & PENDING_RESIZE) != 0) {
- t.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
- }
+ public void configureSurfaceLocked(SurfaceControl.Transaction t) {
if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
setSurfaceLocked(t, mSurface);
+ mPendingChanges &= ~PENDING_SURFACE_CHANGE;
+ }
+ }
+
+ @Override
+ public void configureDisplaySizeLocked(SurfaceControl.Transaction t) {
+ if ((mPendingChanges & PENDING_RESIZE) != 0) {
+ setDisplaySizeLocked(t, mWidth, mHeight);
+ mPendingChanges &= ~PENDING_RESIZE;
}
- mPendingChanges = 0;
}
@Override
@@ -559,14 +572,23 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mInfo.yDpi = mDensityDpi;
mInfo.presentationDeadlineNanos = 1000000000L / (int) getRefreshRate(); // 1 frame
mInfo.flags = 0;
- if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
- mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
- | DisplayDeviceInfo.FLAG_NEVER_BLANK;
- }
- if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
- mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
+ if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
+ }
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
+ }
} else {
- mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
+ | DisplayDeviceInfo.FLAG_NEVER_BLANK;
+ }
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
+ mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
+ } else {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
+ }
}
if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index 607c5d6a88bc..902eefa824b5 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -640,7 +640,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
@Override
- public void performTraversalLocked(SurfaceControl.Transaction t) {
+ public void configureSurfaceLocked(SurfaceControl.Transaction t) {
if (mSurface != null) {
setSurfaceLocked(t, mSurface);
}
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index aab2760dbc66..e4b595ab7c55 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -86,6 +86,11 @@ public class DisplayManagerFlags {
com.android.graphics.surfaceflinger.flags.Flags.FLAG_DISPLAY_CONFIG_ERROR_HAL,
com.android.graphics.surfaceflinger.flags.Flags::displayConfigErrorHal);
+ private final FlagState mSyncedResolutionSwitch = new FlagState(
+ com.android.graphics.surfaceflinger.flags.Flags.FLAG_SYNCED_RESOLUTION_SWITCH,
+ com.android.graphics.surfaceflinger.flags.Flags::syncedResolutionSwitch
+ );
+
private final FlagState mBrightnessIntRangeUserPerceptionFlagState = new FlagState(
Flags.FLAG_BRIGHTNESS_INT_RANGE_USER_PERCEPTION,
Flags::brightnessIntRangeUserPerception);
@@ -275,6 +280,11 @@ public class DisplayManagerFlags {
Flags::refreshRateEventForForegroundApps
);
+ private final FlagState mCommittedStateSeparateEvent = new FlagState(
+ Flags.FLAG_COMMITTED_STATE_SEPARATE_EVENT,
+ Flags::committedStateSeparateEvent
+ );
+
/**
* @return {@code true} if 'port' is allowed in display layout configuration file.
*/
@@ -359,6 +369,10 @@ public class DisplayManagerFlags {
return mDisplayConfigErrorHalFlagState.isEnabled();
}
+ public boolean isSyncedResolutionSwitchEnabled() {
+ return mSyncedResolutionSwitch.isEnabled();
+ }
+
public boolean isBrightnessIntRangeUserPerceptionEnabled() {
return mBrightnessIntRangeUserPerceptionFlagState.isEnabled();
}
@@ -594,6 +608,14 @@ public class DisplayManagerFlags {
}
/**
+ * @return {@code true} if the flag for having a separate event for display's committed state
+ * is enabled
+ */
+ public boolean isCommittedStateSeparateEventEnabled() {
+ return mCommittedStateSeparateEvent.isEnabled();
+ }
+
+ /**
* dumps all flagstates
* @param pw printWriter
*/
@@ -611,6 +633,7 @@ public class DisplayManagerFlags {
pw.println(" " + mEvenDimmerFlagState);
pw.println(" " + mSmallAreaDetectionFlagState);
pw.println(" " + mDisplayConfigErrorHalFlagState);
+ pw.println(" " + mSyncedResolutionSwitch);
pw.println(" " + mBrightnessIntRangeUserPerceptionFlagState);
pw.println(" " + mRestrictDisplayModes);
pw.println(" " + mBrightnessWearBedtimeModeClamperFlagState);
@@ -649,6 +672,7 @@ public class DisplayManagerFlags {
pw.println(" " + mBaseDensityForExternalDisplays);
pw.println(" " + mFramerateOverrideTriggersRrCallbacks);
pw.println(" " + mRefreshRateEventForForegroundApps);
+ pw.println(" " + mCommittedStateSeparateEvent);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 8211febade60..acdc0e0cf891 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -456,9 +456,8 @@ flag {
flag {
name: "enable_display_content_mode_management"
namespace: "lse_desktop_experience"
- description: "Enable switching the content mode of connected displays between mirroring and extened. Also change the default content mode to extended mode."
+ description: "Enable switching the content mode of connected displays between mirroring and extended. Also change the default content mode to extended mode."
bug: "378385869"
- is_fixed_read_only: true
}
flag {
@@ -509,3 +508,14 @@ flag {
bug: "293651324"
is_fixed_read_only: false
}
+
+flag {
+ name: "committed_state_separate_event"
+ namespace: "display_manager"
+ description: "Move Display committed state into a separate event"
+ bug: "342192387"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/flags/people.aconfig b/services/core/java/com/android/server/flags/people.aconfig
new file mode 100644
index 000000000000..532e95848a06
--- /dev/null
+++ b/services/core/java/com/android/server/flags/people.aconfig
@@ -0,0 +1,12 @@
+package: "com.android.server.flags"
+container: "system"
+
+flag {
+ name: "early_data_manager_init"
+ namespace: "system_performance"
+ description: "Initialize DataManager earlier in boot"
+ bug: "394601872"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java
index 94842041af82..ab86433ca50d 100644
--- a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java
+++ b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java
@@ -58,9 +58,9 @@ public interface AudioDeviceVolumeManagerWrapper {
void setDeviceAbsoluteVolumeBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull VolumeInfo volume,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment);
+ @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener);
/**
* Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeAdjustOnlyBehavior(
@@ -69,7 +69,7 @@ public interface AudioDeviceVolumeManagerWrapper {
void setDeviceAbsoluteVolumeAdjustOnlyBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull VolumeInfo volume,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment);
+ @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener);
}
diff --git a/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java
index ff99ace38ef0..10cbb00d2398 100644
--- a/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java
+++ b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java
@@ -61,21 +61,21 @@ public class DefaultAudioDeviceVolumeManagerWrapper
public void setDeviceAbsoluteVolumeBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull VolumeInfo volume,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment) {
- mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeBehavior(device, volume, executor,
- vclistener, handlesVolumeAdjustment);
+ @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener) {
+ mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeBehavior(device, volume,
+ handlesVolumeAdjustment, executor, vclistener);
}
@Override
public void setDeviceAbsoluteVolumeAdjustOnlyBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull VolumeInfo volume,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment) {
+ @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener) {
mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeAdjustOnlyBehavior(device, volume,
- executor, vclistener, handlesVolumeAdjustment);
+ handlesVolumeAdjustment, executor, vclistener);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 3d6d34bf9911..3cb21c3e2697 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1404,6 +1404,9 @@ public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (connected) {
if (mArcEstablished) {
enableAudioReturnChannel(true);
+ } else {
+ HdmiLogger.debug("Restart ARC again");
+ onNewAvrAdded(getAvrDeviceInfo());
}
} else {
enableAudioReturnChannel(false);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 89f0d0edbf2b..6d973ac8d1b5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -4798,15 +4798,15 @@ public class HdmiControlService extends SystemService {
Slog.d(TAG, "Enabling absolute volume behavior");
for (AudioDeviceAttributes device : getAvbCapableAudioOutputDevices()) {
getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeBehavior(
- device, volumeInfo, mServiceThreadExecutor,
- mAbsoluteVolumeChangedListener, true);
+ device, volumeInfo, true, mServiceThreadExecutor,
+ mAbsoluteVolumeChangedListener);
}
} else if (tv() != null) {
Slog.d(TAG, "Enabling adjust-only absolute volume behavior");
for (AudioDeviceAttributes device : getAvbCapableAudioOutputDevices()) {
getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeAdjustOnlyBehavior(
- device, volumeInfo, mServiceThreadExecutor,
- mAbsoluteVolumeChangedListener, true);
+ device, volumeInfo, true, mServiceThreadExecutor,
+ mAbsoluteVolumeChangedListener);
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java
index 87f693cc7291..1ace41cba364 100644
--- a/services/core/java/com/android/server/input/InputManagerInternal.java
+++ b/services/core/java/com/android/server/input/InputManagerInternal.java
@@ -344,4 +344,42 @@ public abstract class InputManagerInternal {
*/
public abstract void applyBackupPayload(Map<Integer, byte[]> payload, int userId)
throws XmlPullParserException, IOException;
+
+ /**
+ * An interface for filtering pointer motion event before cursor position is determined.
+ * <p>
+ * Different from {@code android.view.InputFilter}, this filter can filter motion events at
+ * an early stage of the input pipeline, but only called for pointer's relative motion events.
+ * Unless the user really needs to filter events before the cursor position in the display is
+ * determined, use {@code android.view.InputFilter} instead.
+ */
+ public interface AccessibilityPointerMotionFilter {
+ /**
+ * Called everytime pointer's relative motion event happens.
+ * The returned dx and dy will be used to move the cursor in the display.
+ * <p>
+ * This call happens on the input hot path and it is extremely performance sensitive. It
+ * also must not call back into native code.
+ *
+ * @param dx delta x of the event in pixels.
+ * @param dy delta y of the event in pixels.
+ * @param currentX the cursor x coordinate on the screen before the motion event.
+ * @param currentY the cursor y coordinate on the screen before the motion event.
+ * @param displayId the display ID of the current cursor.
+ * @return an array of length 2, delta x and delta y after filtering the motion. The delta
+ * values are in pixels and must be between 0 and original delta.
+ */
+ @NonNull
+ float[] filterPointerMotionEvent(float dx, float dy, float currentX, float currentY,
+ int displayId);
+ }
+
+ /**
+ * Registers an {@code AccessibilityCursorFilter}.
+ *
+ * @param filter The filter to register. If a filter is already registered, the old filter is
+ * unregistered. {@code null} unregisters the filter that is already registered.
+ */
+ public abstract void registerAccessibilityPointerMotionFilter(
+ @Nullable AccessibilityPointerMotionFilter filter);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 8624f4230e9c..0e37238bcb84 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -25,8 +25,8 @@ import static android.view.KeyEvent.KEYCODE_UNKNOWN;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.hardware.input.Flags.enableCustomizableInputGestures;
-import static com.android.hardware.input.Flags.touchpadVisualizer;
import static com.android.hardware.input.Flags.keyEventActivityDetection;
+import static com.android.hardware.input.Flags.touchpadVisualizer;
import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
import static com.android.server.policy.WindowManagerPolicy.ACTION_PASS_TO_USER;
@@ -193,15 +193,11 @@ public class InputManagerService extends IInputManager.Stub
private static final int MSG_SYSTEM_READY = 5;
private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
- private static final AdditionalDisplayInputProperties
- DEFAULT_ADDITIONAL_DISPLAY_INPUT_PROPERTIES = new AdditionalDisplayInputProperties();
private final NativeInputManagerService mNative;
private final Context mContext;
private final InputManagerHandler mHandler;
- @UserIdInt
- private int mCurrentUserId = UserHandle.USER_SYSTEM;
private DisplayManagerInternal mDisplayManagerInternal;
private WindowManagerInternal mWindowManagerInternal;
@@ -289,7 +285,7 @@ public class InputManagerService extends IInputManager.Stub
final Object mKeyEventActivityLock = new Object();
@GuardedBy("mKeyEventActivityLock")
- private List<IKeyEventActivityListener> mKeyEventActivityListenersToNotify =
+ private final List<IKeyEventActivityListener> mKeyEventActivityListenersToNotify =
new ArrayList<>();
// Rate limit for key event activity detection. Prevent the listener from being notified
@@ -460,6 +456,14 @@ public class InputManagerService extends IInputManager.Stub
private boolean mShowKeyPresses = false;
private boolean mShowRotaryInput = false;
+ /**
+ * A lock for the accessibility pointer motion filter. Don't call native methods while holding
+ * this lock.
+ */
+ private final Object mAccessibilityPointerMotionFilterLock = new Object();
+ private InputManagerInternal.AccessibilityPointerMotionFilter
+ mAccessibilityPointerMotionFilter = null;
+
/** Point of injection for test dependencies. */
@VisibleForTesting
static class Injector {
@@ -2593,6 +2597,23 @@ public class InputManagerService extends IInputManager.Stub
// Native callback.
@SuppressWarnings("unused")
+ final float[] filterPointerMotion(float dx, float dy, float currentX, float currentY,
+ int displayId) {
+ // This call happens on the input hot path and it is extremely performance sensitive.
+ // This must not call back into native code. This is called while the
+ // PointerChoreographer's lock is held.
+ synchronized (mAccessibilityPointerMotionFilterLock) {
+ if (mAccessibilityPointerMotionFilter == null) {
+ throw new IllegalStateException(
+ "filterCursor is invoked but no callback is registered.");
+ }
+ return mAccessibilityPointerMotionFilter.filterPointerMotionEvent(dx, dy, currentX,
+ currentY, displayId);
+ }
+ }
+
+ // Native callback.
+ @SuppressWarnings("unused")
@VisibleForTesting
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
notifyKeyActivityListeners(event);
@@ -3215,7 +3236,6 @@ public class InputManagerService extends IInputManager.Stub
}
private void handleCurrentUserChanged(@UserIdInt int userId) {
- mCurrentUserId = userId;
mKeyGestureController.setCurrentUserId(userId);
}
@@ -3828,6 +3848,12 @@ public class InputManagerService extends IInputManager.Stub
payload.get(BACKUP_CATEGORY_INPUT_GESTURES), userId);
}
}
+
+ @Override
+ public void registerAccessibilityPointerMotionFilter(
+ AccessibilityPointerMotionFilter filter) {
+ InputManagerService.this.registerAccessibilityPointerMotionFilter(filter);
+ }
}
@Override
@@ -4014,6 +4040,26 @@ public class InputManagerService extends IInputManager.Stub
mPointerIconCache.setAccessibilityScaleFactor(displayId, scaleFactor);
}
+ void registerAccessibilityPointerMotionFilter(
+ InputManagerInternal.AccessibilityPointerMotionFilter filter) {
+ // `#filterPointerMotion` expects that when it's called, `mAccessibilityPointerMotionFilter`
+ // is not null.
+ // Also, to avoid potential lock contention, we shouldn't call native method while holding
+ // the lock here. Native code calls `#filterPointerMotion` while PointerChoreographer's
+ // lock is held.
+ // Thus, we must set filter before we enable the filter in native, and reset the filter
+ // after we disable the filter.
+ // This also ensures the previously installed filter isn't called after the filter is
+ // updated.
+ mNative.setAccessibilityPointerMotionFilterEnabled(false);
+ synchronized (mAccessibilityPointerMotionFilterLock) {
+ mAccessibilityPointerMotionFilter = filter;
+ }
+ if (filter != null) {
+ mNative.setAccessibilityPointerMotionFilterEnabled(true);
+ }
+ }
+
interface KeyboardBacklightControllerInterface {
default void incrementKeyboardBacklight(int deviceId) {}
default void decrementKeyboardBacklight(int deviceId) {}
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index f34338a397db..32409d39db3b 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -315,6 +315,16 @@ interface NativeInputManagerService {
*/
boolean setKernelWakeEnabled(int deviceId, boolean enabled);
+ /**
+ * Set whether the accessibility pointer motion filter is enabled.
+ * <p>
+ * Once enabled, {@link InputManagerService#filterPointerMotion} is called for evety motion
+ * event from pointer devices.
+ *
+ * @param enabled {@code true} if the filter is enabled, {@code false} otherwise.
+ */
+ void setAccessibilityPointerMotionFilterEnabled(boolean enabled);
+
/** The native implementation of InputManagerService methods. */
class NativeImpl implements NativeInputManagerService {
/** Pointer to native input manager service object, used by native code. */
@@ -628,5 +638,8 @@ interface NativeInputManagerService {
@Override
public native boolean setKernelWakeEnabled(int deviceId, boolean enabled);
+
+ @Override
+ public native void setAccessibilityPointerMotionFilterEnabled(boolean enabled);
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 484b47022f04..508bc2f811e0 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -365,7 +365,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
return mCurrentImeUserId;
}
- /**
+ /**
* Figures out the target IME user ID associated with the given {@code displayId}.
*
* @param displayId the display ID to be queried about
@@ -649,12 +649,25 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
visibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard(
accessibilitySoftKeyboardSetting);
if (visibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
- hideCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
- 0 /* flags */, SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE, userId);
+ if (Flags.refactorInsetsController()) {
+ final var statsToken = createStatsTokenForFocusedClient(false /* show */,
+ SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE, userId);
+ setImeVisibilityOnFocusedWindowClient(false, userData, statsToken);
+ } else {
+ hideCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
+ 0 /* flags */, SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE,
+ userId);
+ }
} else if (isShowRequestedForCurrentWindow(userId)) {
- showCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
- InputMethodManager.SHOW_IMPLICIT,
- SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE, userId);
+ if (Flags.refactorInsetsController()) {
+ final var statsToken = createStatsTokenForFocusedClient(true /* show */,
+ SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE, userId);
+ setImeVisibilityOnFocusedWindowClient(true, userData, statsToken);
+ } else {
+ showCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
+ InputMethodManager.SHOW_IMPLICIT,
+ SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE, userId);
+ }
}
break;
}
@@ -1319,8 +1332,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
// Do not reset the default (current) IME when it is a 3rd-party IME
String selectedMethodId = bindingController.getSelectedMethodId();
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
- if (selectedMethodId != null && settings.getMethodMap().get(selectedMethodId) != null
- && !settings.getMethodMap().get(selectedMethodId).isSystem()) {
+ final InputMethodInfo selectedImi = settings.getMethodMap().get(selectedMethodId);
+ if (selectedImi != null && !selectedImi.isSystem()) {
return;
}
final List<InputMethodInfo> suitableImes = InputMethodInfoUtils.getDefaultEnabledImes(
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
index 42303e042561..b735b2447486 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
@@ -141,8 +141,7 @@ final class MediaRoute2ProviderWatcher {
isSelfScanOnlyProvider |=
MediaRoute2ProviderService.CATEGORY_SELF_SCAN_ONLY.equals(category);
supportsSystemMediaRouting |=
- MediaRoute2ProviderService.SERVICE_INTERFACE_SYSTEM_MEDIA.equals(
- category);
+ MediaRoute2ProviderService.CATEGORY_SYSTEM_MEDIA.equals(category);
}
}
int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 6c0d8ad7264d..debac9436bb3 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1635,11 +1635,11 @@ class MediaRouter2ServiceImpl {
manager));
}
- List<MediaRoute2Info> routes =
- userRecord.mHandler.mLastNotifiedRoutesToPrivilegedRouters.values().stream()
- .toList();
userRecord.mHandler.sendMessage(
- obtainMessage(ManagerRecord::notifyRoutesUpdated, managerRecord, routes));
+ obtainMessage(
+ UserHandler::dispatchRoutesToManagerOnHandler,
+ userRecord.mHandler,
+ managerRecord));
}
@GuardedBy("mLock")
@@ -2119,6 +2119,9 @@ class MediaRouter2ServiceImpl {
mHasBluetoothRoutingPermission.set(checkCallerHasBluetoothPermissions(mPid, mUid));
boolean newSystemRoutingPermissionValue = hasSystemRoutingPermission();
if (oldSystemRoutingPermissionValue != newSystemRoutingPermissionValue) {
+ // TODO: b/379788233 - Ensure access to fields like
+ // mLastNotifiedRoutesToPrivilegedRouters happens on the right thread. We might need
+ // to run this on the handler.
Map<String, MediaRoute2Info> routesToReport =
newSystemRoutingPermissionValue
? mUserRecord.mHandler.mLastNotifiedRoutesToPrivilegedRouters
@@ -2543,6 +2546,8 @@ class MediaRouter2ServiceImpl {
* both system route providers and user route providers.
*
* <p>See {@link #getRouterRecords(boolean hasModifyAudioRoutingPermission)}.
+ *
+ * <p>Must be accessed on this handler's thread.
*/
private final Map<String, MediaRoute2Info> mLastNotifiedRoutesToPrivilegedRouters =
new ArrayMap<>();
@@ -2558,6 +2563,8 @@ class MediaRouter2ServiceImpl {
* (e.g. volume changes) to non-privileged routers.
*
* <p>See {@link SystemMediaRoute2Provider#mDefaultRoute}.
+ *
+ * <p>Must be accessed on this handler's thread.
*/
private final Map<String, MediaRoute2Info> mLastNotifiedRoutesToNonPrivilegedRouters =
new ArrayMap<>();
@@ -2800,7 +2807,7 @@ class MediaRouter2ServiceImpl {
removedRoutes));
}
- dispatchUpdates(
+ dispatchUpdatesOnHandler(
hasAddedOrModifiedRoutes,
hasRemovedRoutes,
provider.mIsSystemRouteProvider,
@@ -2822,6 +2829,13 @@ class MediaRouter2ServiceImpl {
source, providerId, routesString);
}
+ /** Notifies the given manager of the current routes. */
+ public void dispatchRoutesToManagerOnHandler(ManagerRecord managerRecord) {
+ List<MediaRoute2Info> routes =
+ mLastNotifiedRoutesToPrivilegedRouters.values().stream().toList();
+ managerRecord.notifyRoutesUpdated(routes);
+ }
+
/**
* Dispatches the latest route updates in {@link #mLastNotifiedRoutesToPrivilegedRouters}
* and {@link #mLastNotifiedRoutesToNonPrivilegedRouters} to registered {@link
@@ -2834,7 +2848,7 @@ class MediaRouter2ServiceImpl {
* @param isSystemProvider whether the latest update was caused by a system provider.
* @param defaultRoute the current default route in {@link #mSystemProvider}.
*/
- private void dispatchUpdates(
+ private void dispatchUpdatesOnHandler(
boolean hasAddedOrModifiedRoutes,
boolean hasRemovedRoutes,
boolean isSystemProvider,
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 0b8b115e65d0..91a2843ccaf7 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -120,6 +120,8 @@ public class MediaQualityService extends SystemService {
private final Object mPictureProfileLock = new Object();
// A global lock for sound profile objects.
private final Object mSoundProfileLock = new Object();
+ // A global lock for user state objects.
+ private final Object mUserStateLock = new Object();
// A global lock for ambient backlight objects.
private final Object mAmbientBacklightLock = new Object();
@@ -127,17 +129,17 @@ public class MediaQualityService extends SystemService {
super(context);
mContext = context;
mHalAmbientBacklightCallback = new HalAmbientBacklightCallback();
- mPictureProfileAdjListener = new PictureProfileAdjustmentListenerImpl(mContext);
- mSoundProfileAdjListener = new SoundProfileAdjustmentListenerImpl(mContext);
mPackageManager = mContext.getPackageManager();
mPictureProfileTempIdMap = new BiMap<>();
mSoundProfileTempIdMap = new BiMap<>();
mMediaQualityDbHelper = new MediaQualityDbHelper(mContext);
- mMqDatabaseUtils = new MqDatabaseUtils(mContext);
mMediaQualityDbHelper.setWriteAheadLoggingEnabled(true);
mMediaQualityDbHelper.setIdleConnectionTimeout(30);
- mHalNotifier = new HalNotifier();
mMqManagerNotifier = new MqManagerNotifier();
+ mMqDatabaseUtils = new MqDatabaseUtils();
+ mHalNotifier = new HalNotifier();
+ mPictureProfileAdjListener = new PictureProfileAdjustmentListenerImpl();
+ mSoundProfileAdjListener = new SoundProfileAdjustmentListenerImpl();
// The package info in the context isn't initialized in the way it is for normal apps,
// so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
@@ -166,20 +168,21 @@ public class MediaQualityService extends SystemService {
if (mMediaQuality != null) {
try {
mMediaQuality.setAmbientBacklightCallback(mHalAmbientBacklightCallback);
+
+ mPpChangedListener = mMediaQuality.getPictureProfileListener();
+ mSpChangedListener = mMediaQuality.getSoundProfileListener();
+
mMediaQuality.setPictureProfileAdjustmentListener(mPictureProfileAdjListener);
mMediaQuality.setSoundProfileAdjustmentListener(mSoundProfileAdjListener);
+
} catch (RemoteException e) {
Slog.e(TAG, "Failed to set ambient backlight detector callback", e);
}
}
- mPpChangedListener = IPictureProfileChangedListener.Stub.asInterface(binder);
- mSpChangedListener = ISoundProfileChangedListener.Stub.asInterface(binder);
-
publishBinderService(Context.MEDIA_QUALITY_SERVICE, new BinderService());
}
- // TODO: Add additional APIs. b/373951081
private final class BinderService extends IMediaQualityManager.Stub {
@GuardedBy("mPictureProfileLock")
@@ -225,7 +228,6 @@ public class MediaQualityService extends SystemService {
PictureProfile.ERROR_NO_PERMISSION,
Binder.getCallingUid(), Binder.getCallingPid());
}
-
synchronized (mPictureProfileLock) {
ContentValues values = MediaQualityUtils.getContentValues(dbId,
pp.getProfileType(),
@@ -233,7 +235,6 @@ public class MediaQualityService extends SystemService {
pp.getPackageName(),
pp.getInputId(),
pp.getParameters());
-
updateDatabaseOnPictureProfileAndNotifyManagerAndHal(values, pp.getParameters());
}
}
@@ -269,12 +270,13 @@ public class MediaQualityService extends SystemService {
mMqManagerNotifier.notifyOnPictureProfileError(id,
PictureProfile.ERROR_INVALID_ARGUMENT,
Binder.getCallingUid(), Binder.getCallingPid());
+ } else {
+ mMqManagerNotifier.notifyOnPictureProfileRemoved(
+ mPictureProfileTempIdMap.getValue(dbId), toDelete,
+ Binder.getCallingUid(), Binder.getCallingPid());
+ mPictureProfileTempIdMap.remove(dbId);
+ mHalNotifier.notifyHalOnPictureProfileChange(dbId, null);
}
- mMqManagerNotifier.notifyOnPictureProfileRemoved(
- mPictureProfileTempIdMap.getValue(dbId), toDelete,
- Binder.getCallingUid(), Binder.getCallingPid());
- mPictureProfileTempIdMap.remove(dbId);
- mHalNotifier.notifyHalOnPictureProfileChange(dbId, null);
}
}
}
@@ -520,12 +522,13 @@ public class MediaQualityService extends SystemService {
mMqManagerNotifier.notifyOnSoundProfileError(id,
SoundProfile.ERROR_INVALID_ARGUMENT,
Binder.getCallingUid(), Binder.getCallingPid());
+ } else {
+ mMqManagerNotifier.notifyOnSoundProfileRemoved(
+ mSoundProfileTempIdMap.getValue(dbId), toDelete,
+ Binder.getCallingUid(), Binder.getCallingPid());
+ mSoundProfileTempIdMap.remove(dbId);
+ mHalNotifier.notifyHalOnSoundProfileChange(dbId, null);
}
- mMqManagerNotifier.notifyOnSoundProfileRemoved(
- mSoundProfileTempIdMap.getValue(dbId), toDelete,
- Binder.getCallingUid(), Binder.getCallingPid());
- mSoundProfileTempIdMap.remove(dbId);
- mHalNotifier.notifyHalOnSoundProfileChange(dbId, null);
}
}
}
@@ -684,24 +687,22 @@ public class MediaQualityService extends SystemService {
mContext.getPackageName()) == mPackageManager.PERMISSION_GRANTED;
}
- //TODO: need lock here?
@Override
public void registerPictureProfileCallback(final IPictureProfileCallback callback) {
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
- UserState userState = getOrCreateUserStateLocked(Binder.getCallingUid());
+ UserState userState = getOrCreateUserState(Binder.getCallingUid());
userState.mPictureProfileCallbackPidUidMap.put(callback,
Pair.create(callingPid, callingUid));
}
- //TODO: need lock here?
@Override
public void registerSoundProfileCallback(final ISoundProfileCallback callback) {
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
- UserState userState = getOrCreateUserStateLocked(Binder.getCallingUid());
+ UserState userState = getOrCreateUserState(Binder.getCallingUid());
userState.mSoundProfileCallbackPidUidMap.put(callback,
Pair.create(callingPid, callingUid));
}
@@ -792,7 +793,6 @@ public class MediaQualityService extends SystemService {
}
}
- //TODO: do I need a lock here?
@Override
public List<ParameterCapability> getParameterCapabilities(
List<String> names, UserHandle user) {
@@ -809,14 +809,20 @@ public class MediaQualityService extends SystemService {
private List<ParameterCapability> getListParameterCapability(ParamCapability[] caps) {
List<ParameterCapability> pcList = new ArrayList<>();
- for (ParamCapability pcHal : caps) {
- String name = MediaQualityUtils.getParameterName(pcHal.name);
- boolean isSupported = pcHal.isSupported;
- int type = pcHal.defaultValue == null ? 0 : pcHal.defaultValue.getTag() + 1;
- Bundle bundle = MediaQualityUtils.convertToCaps(type, pcHal.range);
- pcList.add(new ParameterCapability(name, isSupported, type, bundle));
+ if (caps != null) {
+ for (ParamCapability pcHal : caps) {
+ if (pcHal != null) {
+ String name = MediaQualityUtils.getParameterName(pcHal.name);
+ boolean isSupported = pcHal.isSupported;
+ int type = pcHal.defaultValue == null ? 0 : pcHal.defaultValue.getTag() + 1;
+ Bundle bundle = MediaQualityUtils.convertToCaps(type, pcHal.range);
+
+ pcList.add(new ParameterCapability(name, isSupported, type, bundle));
+ }
+ }
}
+
return pcList;
}
@@ -1055,7 +1061,7 @@ public class MediaQualityService extends SystemService {
synchronized (mPictureProfileLock) {
for (int i = 0; i < mUserStates.size(); i++) {
int userId = mUserStates.keyAt(i);
- UserState userState = getOrCreateUserStateLocked(userId);
+ UserState userState = getOrCreateUserState(userId);
userState.mPictureProfileCallbackPidUidMap.remove(callback);
}
}
@@ -1069,7 +1075,7 @@ public class MediaQualityService extends SystemService {
synchronized (mSoundProfileLock) {
for (int i = 0; i < mUserStates.size(); i++) {
int userId = mUserStates.keyAt(i);
- UserState userState = getOrCreateUserStateLocked(userId);
+ UserState userState = getOrCreateUserState(userId);
userState.mSoundProfileCallbackPidUidMap.remove(callback);
}
}
@@ -1095,25 +1101,27 @@ public class MediaQualityService extends SystemService {
}
}
- //TODO: used by both picture and sound. can i add both locks?
- private UserState getOrCreateUserStateLocked(int userId) {
- UserState userState = getUserStateLocked(userId);
+ @GuardedBy("mUserStateLock")
+ private UserState getOrCreateUserState(int userId) {
+ UserState userState = getUserState(userId);
if (userState == null) {
userState = new UserState(mContext, userId);
- mUserStates.put(userId, userState);
+ synchronized (mUserStateLock) {
+ mUserStates.put(userId, userState);
+ }
}
return userState;
}
- //TODO: used by both picture and sound. can i add both locks?
- private UserState getUserStateLocked(int userId) {
- return mUserStates.get(userId);
+ @GuardedBy("mUserStateLock")
+ private UserState getUserState(int userId) {
+ synchronized (mUserStateLock) {
+ return mUserStates.get(userId);
+ }
}
private final class MqDatabaseUtils {
- MediaQualityDbHelper mMediaQualityDbHelper;
-
private PictureProfile getPictureProfile(Long dbId) {
String selection = BaseParameters.PARAMETER_ID + " = ?";
String[] selectionArguments = {Long.toString(dbId)};
@@ -1205,8 +1213,7 @@ public class MediaQualityService extends SystemService {
/*groupBy=*/ null, /*having=*/ null, /*orderBy=*/ null);
}
- private MqDatabaseUtils(Context context) {
- mMediaQualityDbHelper = new MediaQualityDbHelper(context);
+ private MqDatabaseUtils() {
}
}
@@ -1264,7 +1271,7 @@ public class MediaQualityService extends SystemService {
private void notifyPictureProfileHelper(int mode, String profileId,
PictureProfile profile, Integer errorCode,
List<ParameterCapability> paramCaps, int uid, int pid) {
- UserState userState = getOrCreateUserStateLocked(UserHandle.USER_SYSTEM);
+ UserState userState = getOrCreateUserState(UserHandle.USER_SYSTEM);
int n = userState.mPictureProfileCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
@@ -1349,7 +1356,7 @@ public class MediaQualityService extends SystemService {
private void notifySoundProfileHelper(int mode, String profileId,
SoundProfile profile, Integer errorCode,
List<ParameterCapability> paramCaps, int uid, int pid) {
- UserState userState = getOrCreateUserStateLocked(UserHandle.USER_SYSTEM);
+ UserState userState = getOrCreateUserState(UserHandle.USER_SYSTEM);
int n = userState.mSoundProfileCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
@@ -1404,11 +1411,13 @@ public class MediaQualityService extends SystemService {
private void notifyHalOnPictureProfileChange(Long dbId, PersistableBundle params) {
// TODO: only notify HAL when the profile is active / being used
- try {
- mPpChangedListener.onPictureProfileChanged(convertToHalPictureProfile(dbId,
- params));
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to notify HAL on picture profile change.", e);
+ if (mPpChangedListener != null) {
+ try {
+ mPpChangedListener.onPictureProfileChanged(convertToHalPictureProfile(dbId,
+ params));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to notify HAL on picture profile change.", e);
+ }
}
}
@@ -1429,10 +1438,13 @@ public class MediaQualityService extends SystemService {
private void notifyHalOnSoundProfileChange(Long dbId, PersistableBundle params) {
// TODO: only notify HAL when the profile is active / being used
- try {
- mSpChangedListener.onSoundProfileChanged(convertToHalSoundProfile(dbId, params));
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to notify HAL on sound profile change.", e);
+ if (mSpChangedListener != null) {
+ try {
+ mSpChangedListener
+ .onSoundProfileChanged(convertToHalSoundProfile(dbId, params));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to notify HAL on sound profile change.", e);
+ }
}
}
@@ -1488,9 +1500,6 @@ public class MediaQualityService extends SystemService {
private final class PictureProfileAdjustmentListenerImpl extends
IPictureProfileAdjustmentListener.Stub {
- MqDatabaseUtils mMqDatabaseUtils;
- MqManagerNotifier mMqManagerNotifier;
- HalNotifier mHalNotifier;
@Override
public void onPictureProfileAdjusted(
@@ -1542,18 +1551,13 @@ public class MediaQualityService extends SystemService {
return null;
}
- private PictureProfileAdjustmentListenerImpl(Context context) {
- mMqDatabaseUtils = new MqDatabaseUtils(context);
- mMqManagerNotifier = new MqManagerNotifier();
- mHalNotifier = new HalNotifier();
+ private PictureProfileAdjustmentListenerImpl() {
+
}
}
private final class SoundProfileAdjustmentListenerImpl extends
ISoundProfileAdjustmentListener.Stub {
- MqDatabaseUtils mMqDatabaseUtils;
- MqManagerNotifier mMqManagerNotifier;
- HalNotifier mHalNotifier;
@Override
public void onSoundProfileAdjusted(
@@ -1598,10 +1602,8 @@ public class MediaQualityService extends SystemService {
return null;
}
- private SoundProfileAdjustmentListenerImpl(Context context) {
- mMqDatabaseUtils = new MqDatabaseUtils(context);
- mMqManagerNotifier = new MqManagerNotifier();
- mHalNotifier = new HalNotifier();
+ private SoundProfileAdjustmentListenerImpl() {
+
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index b0ef80793cd7..62e26e189a35 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -25,6 +25,8 @@ import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_AUTOBIND;
+import static com.android.server.notification.Flags.FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER;
+import static com.android.server.notification.Flags.managedServicesConcurrentMultiuser;
import static com.android.server.notification.NotificationManagerService.privateSpaceFlagsEnabled;
import android.annotation.FlaggedApi;
@@ -75,7 +77,9 @@ import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.LocalServices;
import com.android.server.notification.NotificationManagerService.DumpFilter;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.TimingsTraceAndSlog;
import org.xmlpull.v1.XmlPullParser;
@@ -134,6 +138,7 @@ abstract public class ManagedServices {
private final UserProfiles mUserProfiles;
protected final IPackageManager mPm;
protected final UserManager mUm;
+ protected final UserManagerInternal mUmInternal;
private final Config mConfig;
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -157,12 +162,17 @@ abstract public class ManagedServices {
protected final ArraySet<String> mDefaultPackages = new ArraySet<>();
// lists the component names of all enabled (and therefore potentially connected)
- // app services for current profiles.
+ // app services for each user. This is intended to support a concurrent multi-user environment.
+ // key value is the resolved userId.
@GuardedBy("mMutex")
- private final ArraySet<ComponentName> mEnabledServicesForCurrentProfiles = new ArraySet<>();
- // Just the packages from mEnabledServicesForCurrentProfiles
+ private final SparseArray<ArraySet<ComponentName>> mEnabledServicesByUser =
+ new SparseArray<>();
+ // Just the packages from mEnabledServicesByUser
+ // This is intended to support a concurrent multi-user environment.
+ // key value is the resolved userId.
@GuardedBy("mMutex")
- private final ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
+ private final SparseArray<ArraySet<String>> mEnabledServicesPackageNamesByUser =
+ new SparseArray<>();
// Per user id, list of enabled packages that have nevertheless asked not to be run
@GuardedBy("mSnoozing")
private final SparseSetArray<ComponentName> mSnoozing = new SparseSetArray<>();
@@ -195,6 +205,10 @@ abstract public class ManagedServices {
mConfig = getConfig();
mApprovalLevel = APPROVAL_BY_COMPONENT;
mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mUmInternal = LocalServices.getService(UserManagerInternal.class);
+ // Initialize for the current user.
+ mEnabledServicesByUser.put(UserHandle.USER_CURRENT, new ArraySet<>());
+ mEnabledServicesPackageNamesByUser.put(UserHandle.USER_CURRENT, new ArraySet<>());
}
abstract protected Config getConfig();
@@ -383,11 +397,30 @@ abstract public class ManagedServices {
}
synchronized (mMutex) {
- pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
- + ") enabled for current profiles:");
- for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
- if (filter != null && !filter.matches(cmpt)) continue;
- pw.println(" " + cmpt);
+ if (managedServicesConcurrentMultiuser()) {
+ for (int i = 0; i < mEnabledServicesByUser.size(); i++) {
+ final int userId = mEnabledServicesByUser.keyAt(i);
+ final ArraySet<ComponentName> componentNames =
+ mEnabledServicesByUser.get(userId);
+ String userString = userId == UserHandle.USER_CURRENT
+ ? "current profiles" : "user " + Integer.toString(userId);
+ pw.println(" All " + getCaption() + "s (" + componentNames.size()
+ + ") enabled for " + userString + ":");
+ for (ComponentName cmpt : componentNames) {
+ if (filter != null && !filter.matches(cmpt)) continue;
+ pw.println(" " + cmpt);
+ }
+ }
+ } else {
+ final ArraySet<ComponentName> enabledServicesForCurrentProfiles =
+ mEnabledServicesByUser.get(UserHandle.USER_CURRENT);
+ pw.println(" All " + getCaption() + "s ("
+ + enabledServicesForCurrentProfiles.size()
+ + ") enabled for current profiles:");
+ for (ComponentName cmpt : enabledServicesForCurrentProfiles) {
+ if (filter != null && !filter.matches(cmpt)) continue;
+ pw.println(" " + cmpt);
+ }
}
pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
@@ -442,11 +475,24 @@ abstract public class ManagedServices {
}
}
-
synchronized (mMutex) {
- for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
- if (filter != null && !filter.matches(cmpt)) continue;
- cmpt.dumpDebug(proto, ManagedServicesProto.ENABLED);
+ if (managedServicesConcurrentMultiuser()) {
+ for (int i = 0; i < mEnabledServicesByUser.size(); i++) {
+ final int userId = mEnabledServicesByUser.keyAt(i);
+ final ArraySet<ComponentName> componentNames =
+ mEnabledServicesByUser.get(userId);
+ for (ComponentName cmpt : componentNames) {
+ if (filter != null && !filter.matches(cmpt)) continue;
+ cmpt.dumpDebug(proto, ManagedServicesProto.ENABLED);
+ }
+ }
+ } else {
+ final ArraySet<ComponentName> enabledServicesForCurrentProfiles =
+ mEnabledServicesByUser.get(UserHandle.USER_CURRENT);
+ for (ComponentName cmpt : enabledServicesForCurrentProfiles) {
+ if (filter != null && !filter.matches(cmpt)) continue;
+ cmpt.dumpDebug(proto, ManagedServicesProto.ENABLED);
+ }
}
for (ManagedServiceInfo info : mServices) {
if (filter != null && !filter.matches(info.component)) continue;
@@ -841,9 +887,31 @@ abstract public class ManagedServices {
}
}
+ /** convenience method for looking in mEnabledServicesPackageNamesByUser
+ * for UserHandle.USER_CURRENT.
+ * This is a legacy API. When FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER becomes
+ * trunk stable, this API should be deprecated. Additionally, when this method
+ * is deprecated, the unit tests written using this method should also be revised.
+ *
+ * @param pkg target package name
+ * @return boolean value that indicates whether it is enabled for the current profiles
+ */
protected boolean isComponentEnabledForPackage(String pkg) {
+ return isComponentEnabledForPackage(pkg, UserHandle.USER_CURRENT);
+ }
+
+ /** convenience method for looking in mEnabledServicesPackageNamesByUser
+ *
+ * @param pkg target package name
+ * @param userId the id of the target user
+ * @return boolean value that indicates whether it is enabled for the target user
+ */
+ @FlaggedApi(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ protected boolean isComponentEnabledForPackage(String pkg, int userId) {
synchronized (mMutex) {
- return mEnabledServicesPackageNames.contains(pkg);
+ ArraySet<String> enabledServicesPackageNames =
+ mEnabledServicesPackageNamesByUser.get(resolveUserId(userId));
+ return enabledServicesPackageNames != null && enabledServicesPackageNames.contains(pkg);
}
}
@@ -1016,9 +1084,14 @@ abstract public class ManagedServices {
public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
if (DEBUG) {
synchronized (mMutex) {
+ int resolvedUserId = (managedServicesConcurrentMultiuser()
+ && (uidList != null && uidList.length > 0))
+ ? resolveUserId(UserHandle.getUserId(uidList[0]))
+ : UserHandle.USER_CURRENT;
Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
+ " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
- + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
+ + " mEnabledServicesPackageNames="
+ + mEnabledServicesPackageNamesByUser.get(resolvedUserId));
}
}
@@ -1034,11 +1107,18 @@ abstract public class ManagedServices {
}
}
for (String pkgName : pkgList) {
- if (isComponentEnabledForPackage(pkgName)) {
- anyServicesInvolved = true;
+ if (!managedServicesConcurrentMultiuser()) {
+ if (isComponentEnabledForPackage(pkgName)) {
+ anyServicesInvolved = true;
+ }
}
if (uidList != null && uidList.length > 0) {
for (int uid : uidList) {
+ if (managedServicesConcurrentMultiuser()) {
+ if (isComponentEnabledForPackage(pkgName, UserHandle.getUserId(uid))) {
+ anyServicesInvolved = true;
+ }
+ }
if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
anyServicesInvolved = true;
trimApprovedListsForInvalidServices(pkgName, UserHandle.getUserId(uid));
@@ -1065,6 +1145,36 @@ abstract public class ManagedServices {
unbindUserServices(user);
}
+ /**
+ * Call this method when a user is stopped
+ *
+ * @param user the id of the stopped user
+ */
+ public void onUserStopped(int user) {
+ if (!managedServicesConcurrentMultiuser()) {
+ return;
+ }
+ boolean hasAny = false;
+ synchronized (mMutex) {
+ if (mEnabledServicesByUser.contains(user)
+ && mEnabledServicesPackageNamesByUser.contains(user)) {
+ // Through the ManagedServices.resolveUserId,
+ // we resolve UserHandle.USER_CURRENT as the key for users
+ // other than the visible background user.
+ // Therefore, the user IDs that exist as keys for each member variable
+ // correspond to the visible background user.
+ // We need to unbind services of the stopped visible background user.
+ mEnabledServicesByUser.remove(user);
+ mEnabledServicesPackageNamesByUser.remove(user);
+ hasAny = true;
+ }
+ }
+ if (hasAny) {
+ Slog.i(TAG, "Removing approved services for stopped user " + user);
+ unbindUserServices(user);
+ }
+ }
+
public void onUserSwitched(int user) {
if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
unbindOtherUserServices(user);
@@ -1386,19 +1496,42 @@ abstract public class ManagedServices {
protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
final IntArray activeUsers,
SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
- mEnabledServicesForCurrentProfiles.clear();
- mEnabledServicesPackageNames.clear();
final int nUserIds = activeUsers.size();
-
+ if (managedServicesConcurrentMultiuser()) {
+ for (int i = 0; i < nUserIds; ++i) {
+ final int resolvedUserId = resolveUserId(activeUsers.get(i));
+ if (mEnabledServicesByUser.get(resolvedUserId) != null) {
+ mEnabledServicesByUser.get(resolvedUserId).clear();
+ }
+ if (mEnabledServicesPackageNamesByUser.get(resolvedUserId) != null) {
+ mEnabledServicesPackageNamesByUser.get(resolvedUserId).clear();
+ }
+ }
+ } else {
+ mEnabledServicesByUser.get(UserHandle.USER_CURRENT).clear();
+ mEnabledServicesPackageNamesByUser.get(UserHandle.USER_CURRENT).clear();
+ }
for (int i = 0; i < nUserIds; ++i) {
- // decode the list of components
final int userId = activeUsers.get(i);
+ // decode the list of components
final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
if (null == userComponents) {
componentsToBind.put(userId, new ArraySet<>());
continue;
}
+ final int resolvedUserId = managedServicesConcurrentMultiuser()
+ ? resolveUserId(userId)
+ : UserHandle.USER_CURRENT;
+ ArraySet<ComponentName> enabledServices =
+ mEnabledServicesByUser.contains(resolvedUserId)
+ ? mEnabledServicesByUser.get(resolvedUserId)
+ : new ArraySet<>();
+ ArraySet<String> enabledServicesPackageName =
+ mEnabledServicesPackageNamesByUser.contains(resolvedUserId)
+ ? mEnabledServicesPackageNamesByUser.get(resolvedUserId)
+ : new ArraySet<>();
+
final Set<ComponentName> add = new HashSet<>(userComponents);
synchronized (mSnoozing) {
ArraySet<ComponentName> snoozed = mSnoozing.get(userId);
@@ -1409,12 +1542,12 @@ abstract public class ManagedServices {
componentsToBind.put(userId, add);
- mEnabledServicesForCurrentProfiles.addAll(userComponents);
-
+ enabledServices.addAll(userComponents);
for (int j = 0; j < userComponents.size(); j++) {
- final ComponentName component = userComponents.valueAt(j);
- mEnabledServicesPackageNames.add(component.getPackageName());
+ enabledServicesPackageName.add(userComponents.valueAt(j).getPackageName());
}
+ mEnabledServicesByUser.put(resolvedUserId, enabledServices);
+ mEnabledServicesPackageNamesByUser.put(resolvedUserId, enabledServicesPackageName);
}
}
@@ -1453,13 +1586,9 @@ abstract public class ManagedServices {
*/
protected void rebindServices(boolean forceRebind, int userToRebind) {
if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
- IntArray userIds = mUserProfiles.getCurrentProfileIds();
boolean rebindAllCurrentUsers = mUserProfiles.isProfileUser(userToRebind, mContext)
&& allowRebindForParentUser();
- if (userToRebind != USER_ALL && !rebindAllCurrentUsers) {
- userIds = new IntArray(1);
- userIds.add(userToRebind);
- }
+ IntArray userIds = getUserIdsForRebindServices(userToRebind, rebindAllCurrentUsers);
final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
@@ -1483,6 +1612,23 @@ abstract public class ManagedServices {
bindToServices(componentsToBind);
}
+ private IntArray getUserIdsForRebindServices(int userToRebind, boolean rebindAllCurrentUsers) {
+ IntArray userIds = mUserProfiles.getCurrentProfileIds();
+ if (userToRebind != USER_ALL && !rebindAllCurrentUsers) {
+ userIds = new IntArray(1);
+ userIds.add(userToRebind);
+ } else if (managedServicesConcurrentMultiuser()
+ && userToRebind == USER_ALL) {
+ for (UserInfo user : mUm.getUsers()) {
+ if (mUmInternal.isVisibleBackgroundFullUser(user.id)
+ && !userIds.contains(user.id)) {
+ userIds.add(user.id);
+ }
+ }
+ }
+ return userIds;
+ }
+
/**
* Called when user switched to unbind all services from other users.
*/
@@ -1506,7 +1652,11 @@ abstract public class ManagedServices {
synchronized (mMutex) {
final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
for (ManagedServiceInfo info : removableBoundServices) {
- if ((allExceptUser && (info.userid != user))
+ // User switching is the event for the forground user.
+ // It should not affect the service of the visible background user.
+ if ((allExceptUser && (info.userid != user)
+ && !(managedServicesConcurrentMultiuser()
+ && info.isVisibleBackgroundUserService))
|| (!allExceptUser && (info.userid == user))) {
Set<ComponentName> toUnbind =
componentsToUnbind.get(info.userid, new ArraySet<>());
@@ -1861,6 +2011,29 @@ abstract public class ManagedServices {
}
/**
+ * This method returns the mapped id for the incoming user id
+ * If the incoming id was not the id of the visible background user, it returns USER_CURRENT.
+ * In the other cases, it returns the same value as the input.
+ *
+ * @param userId the id of the user
+ * @return the user id if it is a visible background user, otherwise
+ * {@link UserHandle#USER_CURRENT}
+ */
+ @FlaggedApi(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ @VisibleForTesting
+ public int resolveUserId(int userId) {
+ if (managedServicesConcurrentMultiuser()) {
+ if (mUmInternal.isVisibleBackgroundFullUser(userId)) {
+ // The dataset of the visible background user should be managed independently.
+ return userId;
+ }
+ }
+ // The data of current user and its profile users need to be managed
+ // in a dataset as before.
+ return UserHandle.USER_CURRENT;
+ }
+
+ /**
* Returns true if services in the parent user should be rebound
* when rebindServices is called with a profile userId.
* Must be false for NotificationAssistants.
@@ -1878,6 +2051,8 @@ abstract public class ManagedServices {
public int targetSdkVersion;
public Pair<ComponentName, Integer> mKey;
public int uid;
+ @FlaggedApi(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public boolean isVisibleBackgroundUserService;
public ManagedServiceInfo(IInterface service, ComponentName component,
int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion,
@@ -1889,6 +2064,10 @@ abstract public class ManagedServices {
this.connection = connection;
this.targetSdkVersion = targetSdkVersion;
this.uid = uid;
+ if (managedServicesConcurrentMultiuser()) {
+ this.isVisibleBackgroundUserService = LocalServices
+ .getService(UserManagerInternal.class).isVisibleBackgroundFullUser(userid);
+ }
mKey = Pair.create(component, userid);
}
@@ -1937,19 +2116,28 @@ abstract public class ManagedServices {
}
public boolean isSameUser(int userId) {
- if (!isEnabledForCurrentProfiles()) {
+ if (!isEnabledForUser()) {
return false;
}
return userId == USER_ALL || userId == this.userid;
}
public boolean enabledAndUserMatches(int nid) {
- if (!isEnabledForCurrentProfiles()) {
+ if (!isEnabledForUser()) {
return false;
}
if (this.userid == USER_ALL) return true;
if (this.isSystem) return true;
if (nid == USER_ALL || nid == this.userid) return true;
+ if (managedServicesConcurrentMultiuser()
+ && mUmInternal.getProfileParentId(nid)
+ != mUmInternal.getProfileParentId(this.userid)) {
+ // If the profile parent IDs do not match each other,
+ // it is determined that the users do not match.
+ // This situation may occur when comparing the current user's ID
+ // with the visible background user's ID.
+ return false;
+ }
return supportsProfiles()
&& mUserProfiles.isCurrentProfile(nid)
&& isPermittedForProfile(nid);
@@ -1969,12 +2157,21 @@ abstract public class ManagedServices {
removeServiceImpl(this.service, this.userid);
}
- /** convenience method for looking in mEnabledServicesForCurrentProfiles */
- public boolean isEnabledForCurrentProfiles() {
+ /**
+ * convenience method for looking in mEnabledServicesByUser.
+ * If FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER is disabled, this manages the data using
+ * only UserHandle.USER_CURRENT as the key, in order to behave the same as the legacy logic.
+ */
+ public boolean isEnabledForUser() {
if (this.isSystem) return true;
if (this.connection == null) return false;
synchronized (mMutex) {
- return mEnabledServicesForCurrentProfiles.contains(this.component);
+ int resolvedUserId = managedServicesConcurrentMultiuser()
+ ? resolveUserId(this.userid)
+ : UserHandle.USER_CURRENT;
+ ArraySet<ComponentName> enabledServices =
+ mEnabledServicesByUser.get(resolvedUserId);
+ return enabledServices != null && enabledServices.contains(this.component);
}
}
@@ -2017,10 +2214,30 @@ abstract public class ManagedServices {
}
}
- /** convenience method for looking in mEnabledServicesForCurrentProfiles */
+ /** convenience method for looking in mEnabledServicesByUser for UserHandle.USER_CURRENT.
+ * This is a legacy API. When FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER becomes
+ * trunk stable, this API should be deprecated. Additionally, when this method
+ * is deprecated, the unit tests written using this method should also be revised.
+ *
+ * @param component target component name
+ * @return boolean value that indicates whether it is enabled for the current profiles
+ */
public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
+ return isComponentEnabledForUser(component, UserHandle.USER_CURRENT);
+ }
+
+ /** convenience method for looking in mEnabledServicesForUser
+ *
+ * @param component target component name
+ * @param userId the id of the target user
+ * @return boolean value that indicates whether it is enabled for the target user
+ */
+ @FlaggedApi(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public boolean isComponentEnabledForUser(ComponentName component, int userId) {
synchronized (mMutex) {
- return mEnabledServicesForCurrentProfiles.contains(component);
+ ArraySet<ComponentName> enabledServicesForUser =
+ mEnabledServicesByUser.get(resolveUserId(userId));
+ return enabledServicesForUser != null && enabledServicesForUser.contains(component);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3a3deb00562e..6fddfb5f90a7 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -173,6 +173,7 @@ import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
import static com.android.server.notification.Flags.expireBitmaps;
+import static com.android.server.notification.Flags.managedServicesConcurrentMultiuser;
import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_ANIM_BUFFER;
import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
@@ -1207,7 +1208,7 @@ public class NotificationManagerService extends SystemService {
}
mAssistants.resetDefaultAssistantsIfNecessary();
- mPreferencesHelper.syncChannelsBypassingDnd();
+ mPreferencesHelper.syncHasPriorityChannels();
}
@VisibleForTesting
@@ -2323,6 +2324,9 @@ public class NotificationManagerService extends SystemService {
if (userHandle >= 0) {
cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle,
REASON_USER_STOPPED);
+ mConditionProviders.onUserStopped(userHandle);
+ mListeners.onUserStopped(userHandle);
+ mAssistants.onUserStopped(userHandle);
}
} else if (
isProfileUnavailable(action)) {
@@ -2343,7 +2347,7 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.onUserSwitched(userId);
mListeners.onUserSwitched(userId);
mZenModeHelper.onUserSwitched(userId);
- mPreferencesHelper.syncChannelsBypassingDnd();
+ mPreferencesHelper.syncHasPriorityChannels();
}
// assistant is the only thing that cares about managed profiles specifically
mAssistants.onUserSwitched(userId);
@@ -2367,7 +2371,7 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.onUserRemoved(userId);
mAssistants.onUserRemoved(userId);
mHistoryManager.onUserRemoved(userId);
- mPreferencesHelper.syncChannelsBypassingDnd();
+ mPreferencesHelper.syncHasPriorityChannels();
handleSavePolicyFile();
} else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
@@ -2376,9 +2380,6 @@ public class NotificationManagerService extends SystemService {
if (!mUserProfiles.isProfileUser(userId, context)) {
mConditionProviders.onUserUnlocked(userId);
mListeners.onUserUnlocked(userId);
- if (!android.app.Flags.modesApi()) {
- mZenModeHelper.onUserUnlocked(userId);
- }
}
}
}
@@ -2767,9 +2768,7 @@ public class NotificationManagerService extends SystemService {
void onPolicyChanged(Policy newPolicy) {
Binder.withCleanCallingIdentity(() -> {
Intent intent = new Intent(ACTION_NOTIFICATION_POLICY_CHANGED);
- if (android.app.Flags.modesApi()) {
- intent.putExtra(EXTRA_NOTIFICATION_POLICY, newPolicy);
- }
+ intent.putExtra(EXTRA_NOTIFICATION_POLICY, newPolicy);
sendRegisteredOnlyBroadcast(intent);
mRankingHandler.requestSort();
});
@@ -2778,11 +2777,10 @@ public class NotificationManagerService extends SystemService {
@Override
void onConsolidatedPolicyChanged(Policy newConsolidatedPolicy) {
Binder.withCleanCallingIdentity(() -> {
- if (android.app.Flags.modesApi()) {
- Intent intent = new Intent(ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED);
- intent.putExtra(EXTRA_NOTIFICATION_POLICY, newConsolidatedPolicy);
- sendRegisteredOnlyBroadcast(intent);
- }
+ Intent intent = new Intent(ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED);
+ intent.putExtra(EXTRA_NOTIFICATION_POLICY, newConsolidatedPolicy);
+ sendRegisteredOnlyBroadcast(intent);
+
mRankingHandler.requestSort();
});
}
@@ -3368,7 +3366,7 @@ public class NotificationManagerService extends SystemService {
migrateDefaultNAS();
maybeShowInitialReviewPermissionsNotification();
- if (android.app.Flags.modesApi() && !mZenModeHelper.hasDeviceEffectsApplier()) {
+ if (!mZenModeHelper.hasDeviceEffectsApplier()) {
// Cannot be done earlier, as some services aren't ready until this point.
mZenModeHelper.setDeviceEffectsApplier(
new DefaultDeviceEffectsApplier(getContext()));
@@ -3446,7 +3444,7 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.onUserSwitched(userId);
mListeners.onUserSwitched(userId);
mZenModeHelper.onUserSwitched(userId);
- mPreferencesHelper.syncChannelsBypassingDnd();
+ mPreferencesHelper.syncHasPriorityChannels();
}
// assistant is the only thing that cares about managed profiles specifically
mAssistants.onUserSwitched(userId);
@@ -5236,11 +5234,23 @@ public class NotificationManagerService extends SystemService {
@Override
public boolean areChannelsBypassingDnd() {
- if (android.app.Flags.modesApi()) {
- return mZenModeHelper.getConsolidatedNotificationPolicy().allowPriorityChannels()
- && mPreferencesHelper.areChannelsBypassingDnd();
+ return mZenModeHelper.getConsolidatedNotificationPolicy().allowPriorityChannels()
+ && mPreferencesHelper.hasPriorityChannels();
+ }
+
+ @Override
+ @FlaggedApi(android.app.Flags.FLAG_NM_BINDER_PERF_GET_APPS_WITH_CHANNELS)
+ public List<String> getPackagesWithAnyChannels(int userId) throws RemoteException {
+ checkCallerIsSystem();
+ UserHandle user = UserHandle.of(userId);
+ List<String> packages = mPreferencesHelper.getPackagesWithAnyChannels(userId);
+ for (int i = packages.size() - 1; i >= 0; i--) {
+ String pkg = packages.get(i);
+ if (!areNotificationsEnabledForPackage(pkg, getUidForPackageAndUser(pkg, user))) {
+ packages.remove(i);
+ }
}
- return mPreferencesHelper.areChannelsBypassingDnd();
+ return packages;
}
@Override
@@ -5715,12 +5725,13 @@ public class NotificationManagerService extends SystemService {
public void requestBindListener(ComponentName component) {
checkCallerIsSystemOrSameApp(component.getPackageName());
int uid = Binder.getCallingUid();
+ int userId = UserHandle.getUserId(uid);
final long identity = Binder.clearCallingIdentity();
try {
- ManagedServices manager =
- mAssistants.isComponentEnabledForCurrentProfiles(component)
- ? mAssistants
- : mListeners;
+ boolean isAssistantEnabled = managedServicesConcurrentMultiuser()
+ ? mAssistants.isComponentEnabledForUser(component, userId)
+ : mAssistants.isComponentEnabledForCurrentProfiles(component);
+ ManagedServices manager = isAssistantEnabled ? mAssistants : mListeners;
manager.setComponentState(component, UserHandle.getUserId(uid), true);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -5747,16 +5758,16 @@ public class NotificationManagerService extends SystemService {
public void requestUnbindListenerComponent(ComponentName component) {
checkCallerIsSameApp(component.getPackageName());
int uid = Binder.getCallingUid();
+ int userId = UserHandle.getUserId(uid);
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationLock) {
- ManagedServices manager =
- mAssistants.isComponentEnabledForCurrentProfiles(component)
- ? mAssistants
- : mListeners;
- if (manager.isPackageOrComponentAllowed(component.flattenToString(),
- UserHandle.getUserId(uid))) {
- manager.setComponentState(component, UserHandle.getUserId(uid), false);
+ boolean isAssistantEnabled = managedServicesConcurrentMultiuser()
+ ? mAssistants.isComponentEnabledForUser(component, userId)
+ : mAssistants.isComponentEnabledForCurrentProfiles(component);
+ ManagedServices manager = isAssistantEnabled ? mAssistants : mListeners;
+ if (manager.isPackageOrComponentAllowed(component.flattenToString(), userId)) {
+ manager.setComponentState(component, userId, false);
}
}
} finally {
@@ -6077,43 +6088,27 @@ public class NotificationManagerService extends SystemService {
@Override
public void requestInterruptionFilterFromListener(INotificationListener token,
int interruptionFilter) throws RemoteException {
- if (android.app.Flags.modesApi()) {
- final int callingUid = Binder.getCallingUid();
- ManagedServiceInfo info;
- synchronized (mNotificationLock) {
- info = mListeners.checkServiceTokenLocked(token);
- }
+ final int callingUid = Binder.getCallingUid();
+ ManagedServiceInfo info;
+ synchronized (mNotificationLock) {
+ info = mListeners.checkServiceTokenLocked(token);
+ }
- final int zenMode = zenModeFromInterruptionFilter(interruptionFilter, -1);
- if (zenMode == -1) return;
+ final int zenMode = zenModeFromInterruptionFilter(interruptionFilter, -1);
+ if (zenMode == -1) return;
- UserHandle zenUser = getCallingZenUser();
- if (!canManageGlobalZenPolicy(info.component.getPackageName(), callingUid)) {
- mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(
- zenUser, info.component.getPackageName(), callingUid, zenMode);
- } else {
- int origin = computeZenOrigin(/* fromUser= */ false);
- Binder.withCleanCallingIdentity(() -> {
- mZenModeHelper.setManualZenMode(zenUser, zenMode, /* conditionId= */ null,
- origin, "listener:" + info.component.flattenToShortString(),
- /* caller= */ info.component.getPackageName(),
- callingUid);
- });
- }
+ UserHandle zenUser = getCallingZenUser();
+ if (!canManageGlobalZenPolicy(info.component.getPackageName(), callingUid)) {
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(
+ zenUser, info.component.getPackageName(), callingUid, zenMode);
} else {
- final int callingUid = Binder.getCallingUid();
- final boolean isSystemOrSystemUi = isCallerSystemOrSystemUi();
- final long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mNotificationLock) {
- final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
- mZenModeHelper.requestFromListener(info.component, interruptionFilter,
- callingUid, isSystemOrSystemUi);
- updateInterruptionFilterLocked();
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ int origin = computeZenOrigin(/* fromUser= */ false);
+ Binder.withCleanCallingIdentity(() -> {
+ mZenModeHelper.setManualZenMode(zenUser, zenMode, /* conditionId= */ null,
+ origin, "listener:" + info.component.flattenToShortString(),
+ /* caller= */ info.component.getPackageName(),
+ callingUid);
+ });
}
}
@@ -6162,19 +6157,8 @@ public class NotificationManagerService extends SystemService {
}
}
- // TODO: b/310620812 - Remove getZenRules() when MODES_API is inlined.
- @Override
- public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
- int callingUid = Binder.getCallingUid();
- enforcePolicyAccess(callingUid, "getZenRules");
- return mZenModeHelper.getZenRules(getCallingZenUser(), callingUid);
- }
-
@Override
public Map<String, AutomaticZenRule> getAutomaticZenRules() {
- if (!android.app.Flags.modesApi()) {
- throw new IllegalStateException("getAutomaticZenRules called with flag off!");
- }
int callingUid = Binder.getCallingUid();
enforcePolicyAccess(callingUid, "getAutomaticZenRules");
return mZenModeHelper.getAutomaticZenRules(getCallingZenUser(), callingUid);
@@ -6245,50 +6229,40 @@ public class NotificationManagerService extends SystemService {
// Implicit rules have no ConditionProvider or Activity. We allow the user to customize
// them (via Settings), but not the owner app. Should the app want to start using it as
// a "normal" rule, it must provide a CP/ConfigActivity too.
- if (android.app.Flags.modesApi()) {
- boolean isImplicitRuleUpdateFromSystem = updateId != null
- && ZenModeConfig.isImplicitRuleId(updateId)
- && isCallerSystemOrSystemUi();
- if (!isImplicitRuleUpdateFromSystem
- && rule.getOwner() == null
- && rule.getConfigurationActivity() == null) {
- throw new NullPointerException(
- "Rule must have a ConditionProviderService and/or configuration "
- + "activity");
- }
- } else {
- if (rule.getOwner() == null && rule.getConfigurationActivity() == null) {
- throw new NullPointerException(
- "Rule must have a ConditionProviderService and/or configuration "
- + "activity");
- }
+ boolean isImplicitRuleUpdateFromSystem = updateId != null
+ && ZenModeConfig.isImplicitRuleId(updateId)
+ && isCallerSystemOrSystemUi();
+ if (!isImplicitRuleUpdateFromSystem
+ && rule.getOwner() == null
+ && rule.getConfigurationActivity() == null) {
+ throw new NullPointerException(
+ "Rule must have a ConditionProviderService and/or configuration "
+ + "activity");
}
Objects.requireNonNull(rule.getConditionId(), "ConditionId is null");
- if (android.app.Flags.modesApi()) {
- if (isCallerSystemOrSystemUi()) {
- return; // System callers can use any type.
- }
- int uid = Binder.getCallingUid();
- int userId = UserHandle.getUserId(uid);
+ if (isCallerSystemOrSystemUi()) {
+ return; // System callers can use any type.
+ }
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getUserId(uid);
- if (rule.getType() == AutomaticZenRule.TYPE_MANAGED) {
- boolean isDeviceOwner = Binder.withCleanCallingIdentity(
- () -> mDpm.isActiveDeviceOwner(uid));
- if (!isDeviceOwner) {
- throw new IllegalArgumentException(
- "Only Device Owners can use AutomaticZenRules with TYPE_MANAGED");
- }
- } else if (rule.getType() == AutomaticZenRule.TYPE_BEDTIME) {
- String wellbeingPackage = getContext().getResources().getString(
- com.android.internal.R.string.config_systemWellbeing);
- boolean isCallerWellbeing = !TextUtils.isEmpty(wellbeingPackage)
- && mPackageManagerInternal.isSameApp(wellbeingPackage, uid, userId);
- if (!isCallerWellbeing) {
- throw new IllegalArgumentException(
- "Only the 'Wellbeing' package can use AutomaticZenRules with "
- + "TYPE_BEDTIME");
- }
+ if (rule.getType() == AutomaticZenRule.TYPE_MANAGED) {
+ boolean isDeviceOwner = Binder.withCleanCallingIdentity(
+ () -> mDpm.isActiveDeviceOwner(uid));
+ if (!isDeviceOwner) {
+ throw new IllegalArgumentException(
+ "Only Device Owners can use AutomaticZenRules with TYPE_MANAGED");
+ }
+ } else if (rule.getType() == AutomaticZenRule.TYPE_BEDTIME) {
+ String wellbeingPackage = getContext().getResources().getString(
+ com.android.internal.R.string.config_systemWellbeing);
+ boolean isCallerWellbeing = !TextUtils.isEmpty(wellbeingPackage)
+ && mPackageManagerInternal.isSameApp(wellbeingPackage, uid, userId);
+ if (!isCallerWellbeing) {
+ throw new IllegalArgumentException(
+ "Only the 'Wellbeing' package can use AutomaticZenRules with "
+ + "TYPE_BEDTIME");
}
}
}
@@ -6371,9 +6345,7 @@ public class NotificationManagerService extends SystemService {
@ZenModeConfig.ConfigOrigin
private int computeZenOrigin(boolean fromUser) {
- // "fromUser" is introduced with MODES_API, so only consider it in that case.
- // (Non-MODES_API behavior should also not depend at all on ORIGIN_USER_IN_X).
- if (android.app.Flags.modesApi() && fromUser) {
+ if (fromUser) {
if (isCallerSystemOrSystemUi()) {
return ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI;
} else {
@@ -6387,9 +6359,7 @@ public class NotificationManagerService extends SystemService {
}
private void enforceUserOriginOnlyFromSystem(boolean fromUser, String method) {
- if (android.app.Flags.modesApi()
- && fromUser
- && !isCallerSystemOrSystemUiOrShell()) {
+ if (fromUser && !isCallerSystemOrSystemUiOrShell()) {
throw new SecurityException(TextUtils.formatSimple(
"Calling %s with fromUser == true is only allowed for system", method));
}
@@ -6404,7 +6374,7 @@ public class NotificationManagerService extends SystemService {
enforceUserOriginOnlyFromSystem(fromUser, "setInterruptionFilter");
UserHandle zenUser = getCallingZenUser();
- if (android.app.Flags.modesApi() && !canManageGlobalZenPolicy(pkg, callingUid)) {
+ if (!canManageGlobalZenPolicy(pkg, callingUid)) {
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(zenUser, pkg, callingUid, zen);
return;
}
@@ -6534,6 +6504,13 @@ public class NotificationManagerService extends SystemService {
} catch (NameNotFoundException e) {
return false;
}
+ if (managedServicesConcurrentMultiuser()) {
+ return checkPackagePolicyAccess(pkg)
+ || mListeners.isComponentEnabledForPackage(pkg,
+ UserHandle.getCallingUserId())
+ || (mDpm != null
+ && (mDpm.isActiveProfileOwner(uid) || mDpm.isActiveDeviceOwner(uid)));
+ }
//TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode.
return checkPackagePolicyAccess(pkg)
|| mListeners.isComponentEnabledForPackage(pkg)
@@ -6708,7 +6685,7 @@ public class NotificationManagerService extends SystemService {
public Policy getNotificationPolicy(String pkg) {
final int callingUid = Binder.getCallingUid();
UserHandle zenUser = getCallingZenUser();
- if (android.app.Flags.modesApi() && !canManageGlobalZenPolicy(pkg, callingUid)) {
+ if (!canManageGlobalZenPolicy(pkg, callingUid)) {
return mZenModeHelper.getNotificationPolicyFromImplicitZenRule(zenUser, pkg);
}
final long identity = Binder.clearCallingIdentity();
@@ -6745,8 +6722,7 @@ public class NotificationManagerService extends SystemService {
UserHandle zenUser = getCallingZenUser();
boolean isSystemCaller = isCallerSystemOrSystemUiOrShell();
- boolean shouldApplyAsImplicitRule = android.app.Flags.modesApi()
- && !canManageGlobalZenPolicy(pkg, callingUid);
+ boolean shouldApplyAsImplicitRule = !canManageGlobalZenPolicy(pkg, callingUid);
final long identity = Binder.clearCallingIdentity();
try {
@@ -6938,7 +6914,8 @@ public class NotificationManagerService extends SystemService {
android.Manifest.permission.INTERACT_ACROSS_USERS,
"setNotificationListenerAccessGrantedForUser for user " + userId);
}
- if (mUmInternal.isVisibleBackgroundFullUser(userId)) {
+ if (!managedServicesConcurrentMultiuser()
+ && mUmInternal.isVisibleBackgroundFullUser(userId)) {
// The main use case for visible background users is the Automotive multi-display
// configuration where a passenger can use a secondary display while the driver is
// using the main display. NotificationListeners is designed only for the current
@@ -8204,9 +8181,6 @@ public class NotificationManagerService extends SystemService {
@Override
public void setDeviceEffectsApplier(DeviceEffectsApplier applier) {
- if (!android.app.Flags.modesApi()) {
- return;
- }
if (mZenModeHelper == null) {
throw new IllegalStateException("ZenModeHelper is not yet ready!");
}
@@ -13150,7 +13124,8 @@ public class NotificationManagerService extends SystemService {
@Override
public void onUserUnlocked(int user) {
- if (mUmInternal.isVisibleBackgroundFullUser(user)) {
+ if (!managedServicesConcurrentMultiuser()
+ && mUmInternal.isVisibleBackgroundFullUser(user)) {
// The main use case for visible background users is the Automotive
// multi-display configuration where a passenger can use a secondary
// display while the driver is using the main display.
@@ -13790,7 +13765,7 @@ public class NotificationManagerService extends SystemService {
// TODO (b/73052211): if the ranking update changed the notification type,
// cancel notifications for NLSes that can't see them anymore
for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
+ if (!serviceInfo.isEnabledForUser() || !isInteractionVisibleToListener(
serviceInfo, ActivityManager.getCurrentUser())) {
continue;
}
@@ -13818,7 +13793,7 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
public void notifyListenerHintsChangedLocked(final int hints) {
for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
+ if (!serviceInfo.isEnabledForUser() || !isInteractionVisibleToListener(
serviceInfo, ActivityManager.getCurrentUser())) {
continue;
}
@@ -13874,7 +13849,7 @@ public class NotificationManagerService extends SystemService {
public void notifyInterruptionFilterChanged(final int interruptionFilter) {
for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
+ if (!serviceInfo.isEnabledForUser() || !isInteractionVisibleToListener(
serviceInfo, ActivityManager.getCurrentUser())) {
continue;
}
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index c305d66c24c1..bc987ed21251 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -183,13 +183,8 @@ public class NotificationShellCmd extends ShellCommand {
interruptionFilter = INTERRUPTION_FILTER_ALL;
}
final int filter = interruptionFilter;
- if (android.app.Flags.modesApi()) {
- mBinderService.setInterruptionFilter(callingPackage, filter,
- /* fromUser= */ true);
- } else {
- mBinderService.setInterruptionFilter(callingPackage, filter,
- /* fromUser= */ false);
- }
+ mBinderService.setInterruptionFilter(callingPackage, filter,
+ /* fromUser= */ true);
}
break;
case "allow_dnd": {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index a171ffc2ed98..0fc182f3f1bb 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -233,11 +233,9 @@ public class PreferencesHelper implements RankingConfig {
private SparseBooleanArray mLockScreenShowNotifications;
private SparseBooleanArray mLockScreenPrivateNotifications;
private boolean mIsMediaNotificationFilteringEnabled;
- // When modes_api flag is enabled, this value only tracks whether the current user has any
- // channels marked as "priority channels", but not necessarily whether they are permitted
- // to bypass DND by current zen policy.
- // TODO: b/310620812 - Rename to be more accurate when modes_api flag is inlined.
- private boolean mCurrentUserHasChannelsBypassingDnd;
+ // Whether the current user has any channels marked as "priority channels" -- but not
+ // necessarily whether they are permitted to bypass DND by current zen policy.
+ private boolean mCurrentUserHasPriorityChannels;
private boolean mHideSilentStatusBarIcons = DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS;
private final boolean mShowReviewPermissionsNotification;
@@ -1063,7 +1061,7 @@ public class PreferencesHelper implements RankingConfig {
r.groups.put(group.getId(), group);
}
if (needsDndChange) {
- updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
+ updateCurrentUserHasPriorityChannels(callingUid, fromSystemOrSystemUi);
}
if (android.app.Flags.nmBinderPerfCacheChannels() && changed) {
invalidateNotificationChannelGroupCache();
@@ -1150,7 +1148,7 @@ public class PreferencesHelper implements RankingConfig {
existing.setBypassDnd(bypassDnd);
needsPolicyFileChange = true;
- if (bypassDnd != mCurrentUserHasChannelsBypassingDnd
+ if (bypassDnd != mCurrentUserHasPriorityChannels
|| previousExistingImportance != existing.getImportance()) {
needsDndChange = true;
}
@@ -1214,7 +1212,7 @@ public class PreferencesHelper implements RankingConfig {
}
r.channels.put(channel.getId(), channel);
- if (channel.canBypassDnd() != mCurrentUserHasChannelsBypassingDnd) {
+ if (channel.canBypassDnd() != mCurrentUserHasPriorityChannels) {
needsDndChange = true;
}
MetricsLogger.action(getChannelLog(channel, pkg).setType(
@@ -1224,7 +1222,7 @@ public class PreferencesHelper implements RankingConfig {
}
if (needsDndChange) {
- updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
+ updateCurrentUserHasPriorityChannels(callingUid, fromSystemOrSystemUi);
}
if (android.app.Flags.nmBinderPerfCacheChannels() && needsPolicyFileChange) {
@@ -1317,14 +1315,14 @@ public class PreferencesHelper implements RankingConfig {
// relevantly affected without the parent channel already having been.
}
- if (updatedChannel.canBypassDnd() != mCurrentUserHasChannelsBypassingDnd
+ if (updatedChannel.canBypassDnd() != mCurrentUserHasPriorityChannels
|| channel.getImportance() != updatedChannel.getImportance()) {
needsDndChange = true;
changed = true;
}
}
if (needsDndChange) {
- updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
+ updateCurrentUserHasPriorityChannels(callingUid, fromSystemOrSystemUi);
}
if (changed) {
if (android.app.Flags.nmBinderPerfCacheChannels()) {
@@ -1550,7 +1548,7 @@ public class PreferencesHelper implements RankingConfig {
}
}
if (channelBypassedDnd) {
- updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
+ updateCurrentUserHasPriorityChannels(callingUid, fromSystemOrSystemUi);
}
if (android.app.Flags.nmBinderPerfCacheChannels() && deletedChannel) {
@@ -1745,7 +1743,7 @@ public class PreferencesHelper implements RankingConfig {
}
}
if (groupBypassedDnd) {
- updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
+ updateCurrentUserHasPriorityChannels(callingUid, fromSystemOrSystemUi);
}
if (android.app.Flags.nmBinderPerfCacheChannels()) {
if (deletedChannels.size() > 0) {
@@ -1906,8 +1904,8 @@ public class PreferencesHelper implements RankingConfig {
}
}
if (!deletedChannelIds.isEmpty()) {
- if (mCurrentUserHasChannelsBypassingDnd) {
- updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
+ if (mCurrentUserHasPriorityChannels) {
+ updateCurrentUserHasPriorityChannels(callingUid, fromSystemOrSystemUi);
}
if (android.app.Flags.nmBinderPerfCacheChannels()) {
invalidateNotificationChannelCache();
@@ -2006,6 +2004,29 @@ public class PreferencesHelper implements RankingConfig {
}
/**
+ * Gets all apps for this user that have a nonzero number of channels. This count does not
+ * include deleted channels.
+ */
+ @FlaggedApi(android.app.Flags.FLAG_NM_BINDER_PERF_GET_APPS_WITH_CHANNELS)
+ public @NonNull List<String> getPackagesWithAnyChannels(@UserIdInt int userId) {
+ List<String> pkgs = new ArrayList<>();
+ synchronized (mLock) {
+ for (PackagePreferences p : mPackagePreferences.values()) {
+ if (UserHandle.getUserId(p.uid) != userId) {
+ continue;
+ }
+ for (NotificationChannel c : p.channels.values()) {
+ if (!c.isDeleted()) {
+ pkgs.add(p.pkg);
+ break;
+ }
+ }
+ }
+ }
+ return pkgs;
+ }
+
+ /**
* True for pre-O apps that only have the default channel, or pre O apps that have no
* channels yet. This method will create the default channel for pre-O apps that don't have it.
* Should never be true for O+ targeting apps, but that's enforced on boot/when an app
@@ -2075,7 +2096,7 @@ public class PreferencesHelper implements RankingConfig {
}
/**
- * Syncs {@link #mCurrentUserHasChannelsBypassingDnd} with the current user's notification
+ * Syncs {@link #mCurrentUserHasPriorityChannels} with the current user's notification
* policy before updating. Must be called:
* <ul>
* <li>On system init, after channels and DND configurations are loaded.
@@ -2083,22 +2104,23 @@ public class PreferencesHelper implements RankingConfig {
* <li>If users are removed (the removed user could've been a profile of the current one).
* </ul>
*/
- void syncChannelsBypassingDnd() {
- mCurrentUserHasChannelsBypassingDnd =
+ void syncHasPriorityChannels() {
+ mCurrentUserHasPriorityChannels =
(mZenModeHelper.getNotificationPolicy(UserHandle.CURRENT).state
- & NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) != 0;
+ & NotificationManager.Policy.STATE_HAS_PRIORITY_CHANNELS) != 0;
- updateCurrentUserHasChannelsBypassingDnd(/* callingUid= */ Process.SYSTEM_UID,
+ updateCurrentUserHasPriorityChannels(/* callingUid= */ Process.SYSTEM_UID,
/* fromSystemOrSystemUi= */ true);
}
/**
* Updates the user's NotificationPolicy based on whether the current userId has channels
- * bypassing DND. It should be called whenever a channel is created, updated, or deleted, or
- * when the current user (or its profiles) change.
+ * marked as "priority" (which might bypass DND, depending on the zen rule details). It should
+ * be called whenever a channel is created, updated, or deleted, or when the current user (or
+ * its profiles) change.
*/
// TODO: b/368247671 - remove fromSystemOrSystemUi argument when modes_ui is inlined.
- private void updateCurrentUserHasChannelsBypassingDnd(int callingUid,
+ private void updateCurrentUserHasPriorityChannels(int callingUid,
boolean fromSystemOrSystemUi) {
ArraySet<Pair<String, Integer>> candidatePkgs = new ArraySet<>();
@@ -2126,13 +2148,13 @@ public class PreferencesHelper implements RankingConfig {
}
}
boolean haveBypassingApps = candidatePkgs.size() > 0;
- if (mCurrentUserHasChannelsBypassingDnd != haveBypassingApps) {
- mCurrentUserHasChannelsBypassingDnd = haveBypassingApps;
+ if (mCurrentUserHasPriorityChannels != haveBypassingApps) {
+ mCurrentUserHasPriorityChannels = haveBypassingApps;
if (android.app.Flags.modesUi()) {
mZenModeHelper.updateHasPriorityChannels(UserHandle.CURRENT,
- mCurrentUserHasChannelsBypassingDnd);
+ mCurrentUserHasPriorityChannels);
} else {
- updateZenPolicy(mCurrentUserHasChannelsBypassingDnd, callingUid,
+ updateZenPolicy(mCurrentUserHasPriorityChannels, callingUid,
fromSystemOrSystemUi);
}
}
@@ -2165,16 +2187,20 @@ public class PreferencesHelper implements RankingConfig {
policy.priorityCategories, policy.priorityCallSenders,
policy.priorityMessageSenders, policy.suppressedVisualEffects,
(areChannelsBypassingDnd
- ? NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND : 0),
+ ? NotificationManager.Policy.STATE_HAS_PRIORITY_CHANNELS : 0),
policy.priorityConversationSenders),
fromSystemOrSystemUi ? ZenModeConfig.ORIGIN_SYSTEM
: ZenModeConfig.ORIGIN_APP,
callingUid);
}
- // TODO: b/310620812 - rename to hasPriorityChannels() when modes_api is inlined.
- public boolean areChannelsBypassingDnd() {
- return mCurrentUserHasChannelsBypassingDnd;
+ /**
+ * Whether the current user has any channels marked as "priority channels"
+ * ({@link NotificationChannel#canBypassDnd}), but not necessarily whether they are permitted
+ * to bypass the filters set by the current zen policy.
+ */
+ public boolean hasPriorityChannels() {
+ return mCurrentUserHasPriorityChannels;
}
/**
diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
index fcc5e9771f94..ec9a2db52de9 100644
--- a/services/core/java/com/android/server/notification/ZenModeEventLogger.java
+++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
@@ -16,7 +16,7 @@
package com.android.server.notification;
-import static android.app.NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND;
+import static android.app.NotificationManager.Policy.STATE_HAS_PRIORITY_CHANNELS;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
import static android.service.notification.NotificationServiceProto.CHANNEL_POLICY_NONE;
import static android.service.notification.NotificationServiceProto.CHANNEL_POLICY_PRIORITY;
@@ -285,11 +285,10 @@ class ZenModeEventLogger {
return true;
}
- if (Flags.modesApi() && hasActiveRuleCountDiff()) {
- // Rules with INTERRUPTION_FILTER_ALL were always possible but before MODES_API
- // they were completely useless; now they can apply effects, so we want to log
- // when they become active/inactive, even though DND itself (as in "notification
- // blocking") is off.
+ if (hasActiveRuleCountDiff()) {
+ // Rules with INTERRUPTION_FILTER_ALL can apply effects, so we want to log when they
+ // become active/inactive, even though DND itself (as in "notification blocking")
+ // is off.
return true;
}
@@ -331,7 +330,7 @@ class ZenModeEventLogger {
}
}
- if (Flags.modesApi() && mNewZenMode == ZEN_MODE_OFF) {
+ if (mNewZenMode == ZEN_MODE_OFF) {
// If the mode is OFF -> OFF then there cannot be any *effective* change to policy.
// (Note that, in theory, a policy diff is impossible since we don't merge the
// policies of INTERRUPTION_FILTER_ALL rules; this is a "just in case" check).
@@ -439,24 +438,14 @@ class ZenModeEventLogger {
// Determine the number of (automatic & manual) rules active after the change takes place.
int getNumRulesActive() {
- if (!Flags.modesApi()) {
- // If the zen mode has turned off, that means nothing can be active.
- if (mNewZenMode == ZEN_MODE_OFF) {
- return 0;
- }
- }
return numActiveRulesInConfig(mNewConfig);
}
/**
- * Return a list of the types of each of the active rules in the configuration.
- * Only available when {@code MODES_API} is active; otherwise returns an empty list.
+ * Return a list of the types of each of the active rules in the configuration (sorted by
+ * the numerical value of the type, and including duplicates).
*/
int[] getActiveRuleTypes() {
- if (!Flags.modesApi()) {
- return new int[0];
- }
-
ArrayList<Integer> activeTypes = new ArrayList<>();
List<ZenRule> activeRules = activeRulesList(mNewConfig);
if (activeRules.size() == 0) {
@@ -476,77 +465,10 @@ class ZenModeEventLogger {
return out;
}
- /**
- * Return our best guess as to whether the changes observed are due to a user action.
- * Note that this (before {@code MODES_API}) won't be 100% accurate as we can't necessarily
- * distinguish between a system uid call indicating "user interacted with Settings" vs "a
- * system app changed something automatically".
- */
+ /** Return whether the changes observed are due to a user action. */
boolean getIsUserAction() {
- if (Flags.modesApi()) {
- return mOrigin == ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI
- || mOrigin == ZenModeConfig.ORIGIN_USER_IN_APP;
- }
-
- // Approach for pre-MODES_API:
- // - if manual rule turned on or off, the calling UID is system, and the new manual
- // rule does not have an enabler set, guess that this is likely to be a user action.
- // This may represent a system app turning on DND automatically, but we guess "user"
- // in this case.
- // - note that this has a known failure mode of "manual rule turning off
- // automatically after the default time runs out". We currently have no way
- // of distinguishing this case from a user manually turning off the rule.
- // - the reason for checking the enabler field is that a call may look like it's
- // coming from a system UID, but if an enabler is set then the request came
- // from an external source. "enabler" will be blank when manual rule is turned
- // on from Quick Settings or Settings.
- // - if an automatic rule's state changes in whether it is "enabled", then
- // that is probably a user action.
- // - if an automatic rule goes from "not snoozing" to "snoozing", that is probably
- // a user action; that means that the user temporarily turned off DND associated
- // with that rule.
- // - if an automatic rule becomes active but does *not* change in its enabled state
- // (covered by a previous case anyway), we guess that this is an automatic change.
- // - if a rule is added or removed and the call comes from the system, we guess that
- // this is a user action (as system rules can't be added or removed without a user
- // action).
- switch (getChangedRuleType()) {
- case RULE_TYPE_MANUAL:
- // TODO(b/278888961): Distinguish the automatically-turned-off state
- return isFromSystemOrSystemUi() && (getNewManualRuleEnabler() == null);
- case RULE_TYPE_AUTOMATIC:
- for (ZenModeDiff.RuleDiff d : getChangedAutomaticRules().values()) {
- if (d.wasAdded() || d.wasRemoved()) {
- // If the change comes from system, a rule being added/removed indicates
- // a likely user action. From an app, it's harder to know for sure.
- return isFromSystemOrSystemUi();
- }
- ZenModeDiff.FieldDiff enabled = d.getDiffForField(
- ZenModeDiff.RuleDiff.FIELD_ENABLED);
- if (enabled != null && enabled.hasDiff()) {
- return true;
- }
- ZenModeDiff.FieldDiff snoozing = d.getDiffForField(
- ZenModeDiff.RuleDiff.FIELD_SNOOZING);
- if (snoozing != null && snoozing.hasDiff() && (boolean) snoozing.to()) {
- return true;
- }
- }
- // If the change was in an automatic rule and none of the "probably triggered
- // by a user" cases apply, then it's probably an automatic change.
- return false;
- case RULE_TYPE_UNKNOWN:
- default:
- }
-
- // If the change wasn't in a rule, but was in the zen policy: consider to be user action
- // if the calling uid is system
- if (hasPolicyDiff() || hasChannelsBypassingDiff()) {
- return mCallingUid == Process.SYSTEM_UID;
- }
-
- // don't know, or none of the other things triggered; assume not a user action
- return false;
+ return mOrigin == ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI
+ || mOrigin == ZenModeConfig.ORIGIN_USER_IN_APP;
}
boolean isFromSystemOrSystemUi() {
@@ -587,7 +509,7 @@ class ZenModeEventLogger {
*/
@Nullable
byte[] getDNDPolicyProto() {
- if (Flags.modesApi() && mNewZenMode == ZEN_MODE_OFF) {
+ if (mNewZenMode == ZEN_MODE_OFF) {
return null;
}
@@ -628,13 +550,10 @@ class ZenModeEventLogger {
mNewPolicy.allowMessagesFrom()));
proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM,
mNewPolicy.allowConversationsFrom());
-
- if (Flags.modesApi()) {
- proto.write(DNDPolicyProto.ALLOW_CHANNELS,
- mNewPolicy.allowPriorityChannels()
- ? CHANNEL_POLICY_PRIORITY
- : CHANNEL_POLICY_NONE);
- }
+ proto.write(DNDPolicyProto.ALLOW_CHANNELS,
+ mNewPolicy.allowPriorityChannels()
+ ? CHANNEL_POLICY_PRIORITY
+ : CHANNEL_POLICY_NONE);
} else {
Log.wtf(TAG, "attempted to write zen mode log event with null policy");
}
@@ -648,14 +567,14 @@ class ZenModeEventLogger {
*/
boolean getAreChannelsBypassing() {
if (mNewPolicy != null) {
- return (mNewPolicy.state & STATE_CHANNELS_BYPASSING_DND) != 0;
+ return (mNewPolicy.state & STATE_HAS_PRIORITY_CHANNELS) != 0;
}
return false;
}
private boolean hasChannelsBypassingDiff() {
boolean prevChannelsBypassing = mPrevPolicy != null
- ? (mPrevPolicy.state & STATE_CHANNELS_BYPASSING_DND) != 0 : false;
+ ? (mPrevPolicy.state & STATE_HAS_PRIORITY_CHANNELS) != 0 : false;
return prevChannelsBypassing != getAreChannelsBypassing();
}
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index bdca555707e3..87ae78195ff5 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -19,7 +19,6 @@ package com.android.server.notification;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE;
-import android.app.Flags;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.ComponentName;
@@ -146,16 +145,12 @@ public class ZenModeFiltering {
// Returns whether the record is permitted to bypass DND when the zen mode is
// ZEN_MODE_IMPORTANT_INTERRUPTIONS. This depends on whether the record's package priority is
- // marked as PRIORITY_MAX (an indication of it belonging to a priority channel), and, if
- // the modes_api flag is on, whether the given policy permits priority channels to bypass.
- // TODO: b/310620812 - simplify when modes_api is inlined.
+ // marked as PRIORITY_MAX (an indication of it belonging to a priority channel), and whether the
+ // given policy permits priority channels to bypass.
private boolean canRecordBypassDnd(NotificationRecord record,
NotificationManager.Policy policy) {
boolean inPriorityChannel = record.getPackagePriority() == Notification.PRIORITY_MAX;
- if (Flags.modesApi()) {
- return inPriorityChannel && policy.allowPriorityChannels();
- }
- return inPriorityChannel;
+ return inPriorityChannel && policy.allowPriorityChannels();
}
/**
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index b39b6fde6258..889df512dd60 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -157,6 +157,12 @@ public class ZenModeHelper {
static final int RULE_LIMIT_PER_PACKAGE = 100;
private static final Duration DELETED_RULE_KEPT_FOR = Duration.ofDays(30);
+ /**
+ * Amount of time since last activation after which implicit rules that have never been
+ * customized by the user are automatically cleaned up.
+ */
+ private static final Duration IMPLICIT_RULE_KEPT_FOR = Duration.ofDays(30);
+
private static final int MAX_ICON_RESOURCE_NAME_LENGTH = 1000;
/**
@@ -326,9 +332,6 @@ public class ZenModeHelper {
* applied immediately.
*/
void setDeviceEffectsApplier(@NonNull DeviceEffectsApplier deviceEffectsApplier) {
- if (!Flags.modesApi()) {
- return;
- }
synchronized (mConfigLock) {
if (mDeviceEffectsApplier != null) {
throw new IllegalStateException("Already set up a DeviceEffectsApplier!");
@@ -350,11 +353,6 @@ public class ZenModeHelper {
}
}
- // TODO: b/310620812 - Remove when MODES_API is inlined (no more callers).
- public void onUserUnlocked(int user) {
- loadConfigForUser(user, "onUserUnlocked");
- }
-
void setPriorityOnlyDndExemptPackages(String[] packages) {
mPriorityOnlyDndExemptPackages = packages;
}
@@ -385,21 +383,6 @@ public class ZenModeHelper {
return NotificationManager.zenModeToInterruptionFilter(mZenMode);
}
- // TODO: b/310620812 - Remove when MODES_API is inlined (no more callers).
- public void requestFromListener(ComponentName name, int filter, int callingUid,
- boolean fromSystemOrSystemUi) {
- final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
- if (newZen != -1) {
- // This change is known to be for UserHandle.CURRENT because NLSes for
- // background users are unbound.
- setManualZenMode(UserHandle.CURRENT, newZen, null,
- fromSystemOrSystemUi ? ORIGIN_SYSTEM : ORIGIN_APP,
- /* reason= */ "listener:" + (name != null ? name.flattenToShortString() : null),
- /* caller= */ name != null ? name.getPackageName() : null,
- callingUid);
- }
- }
-
public void setSuppressedEffects(long suppressedEffects) {
if (mSuppressedEffects == suppressedEffects) return;
mSuppressedEffects = suppressedEffects;
@@ -414,33 +397,24 @@ public class ZenModeHelper {
return mZenMode;
}
- // TODO: b/310620812 - Make private (or inline) when MODES_API is inlined.
- public List<ZenRule> getZenRules(UserHandle user, int callingUid) {
- List<ZenRule> rules = new ArrayList<>();
+ /**
+ * Get the list of {@link AutomaticZenRule} instances that the calling package can manage
+ * (which means the owned rules for a regular app, and every rule for system callers) together
+ * with their ids.
+ */
+ Map<String, AutomaticZenRule> getAutomaticZenRules(UserHandle user, int callingUid) {
+ HashMap<String, AutomaticZenRule> rules = new HashMap<>();
synchronized (mConfigLock) {
ZenModeConfig config = getConfigLocked(user);
if (config == null) return rules;
+
for (ZenRule rule : config.automaticRules.values()) {
if (canManageAutomaticZenRule(rule, callingUid)) {
- rules.add(rule);
+ rules.put(rule.id, zenRuleToAutomaticZenRule(rule));
}
}
+ return rules;
}
- return rules;
- }
-
- /**
- * Get the list of {@link AutomaticZenRule} instances that the calling package can manage
- * (which means the owned rules for a regular app, and every rule for system callers) together
- * with their ids.
- */
- Map<String, AutomaticZenRule> getAutomaticZenRules(UserHandle user, int callingUid) {
- List<ZenRule> ruleList = getZenRules(user, callingUid);
- HashMap<String, AutomaticZenRule> rules = new HashMap<>(ruleList.size());
- for (ZenRule rule : ruleList) {
- rules.put(rule.id, zenRuleToAutomaticZenRule(rule));
- }
- return rules;
}
public AutomaticZenRule getAutomaticZenRule(UserHandle user, String id, int callingUid) {
@@ -511,9 +485,6 @@ public class ZenModeHelper {
@GuardedBy("mConfigLock")
private ZenRule maybeRestoreRemovedRule(ZenModeConfig config, String pkg, ZenRule ruleToAdd,
AutomaticZenRule azrToAdd, @ConfigOrigin int origin) {
- if (!Flags.modesApi()) {
- return ruleToAdd;
- }
String deletedKey = ZenModeConfig.deletedRuleKey(ruleToAdd);
if (deletedKey == null) {
// Couldn't calculate the deletedRuleKey (condition or pkg null?). This should
@@ -561,9 +532,6 @@ public class ZenModeHelper {
*/
private static void maybeReplaceDefaultRule(ZenModeConfig config, @Nullable ZenRule oldRule,
AutomaticZenRule rule) {
- if (!Flags.modesApi()) {
- return;
- }
if (rule.getType() == AutomaticZenRule.TYPE_BEDTIME
&& (oldRule == null || oldRule.type != rule.getType())) {
// Note: we must not verify canManageAutomaticZenRule here, since most likely they
@@ -572,7 +540,7 @@ public class ZenModeHelper {
ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
if (sleepingRule != null
&& !sleepingRule.enabled
- && sleepingRule.canBeUpdatedByApp() /* meaning it's not user-customized */) {
+ && !sleepingRule.isUserModified()) {
config.automaticRules.remove(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
}
}
@@ -599,18 +567,10 @@ public class ZenModeHelper {
}
ZenModeConfig newConfig = config.copy();
ZenModeConfig.ZenRule newRule = requireNonNull(newConfig.automaticRules.get(ruleId));
- if (!Flags.modesApi()) {
- if (newRule.enabled != automaticZenRule.isEnabled()) {
- dispatchOnAutomaticRuleStatusChanged(config.user, newRule.getPkg(), ruleId,
- automaticZenRule.isEnabled()
- ? AUTOMATIC_RULE_STATUS_ENABLED
- : AUTOMATIC_RULE_STATUS_DISABLED);
- }
- }
boolean updated = populateZenRule(newRule.pkg, automaticZenRule, newConfig, newRule,
origin, /* isNew= */ false);
- if (Flags.modesApi() && !updated) {
+ if (!updated) {
// Bail out so we don't have the side effects of updating a rule (i.e. dropping
// condition) when no changes happen.
return true;
@@ -643,10 +603,6 @@ public class ZenModeHelper {
*/
void applyGlobalZenModeAsImplicitZenRule(UserHandle user, String callingPkg, int callingUid,
int zenMode) {
- if (!android.app.Flags.modesApi()) {
- Log.wtf(TAG, "applyGlobalZenModeAsImplicitZenRule called with flag off!");
- return;
- }
synchronized (mConfigLock) {
ZenModeConfig config = getConfigLocked(user);
if (config == null) {
@@ -712,10 +668,6 @@ public class ZenModeHelper {
*/
void applyGlobalPolicyAsImplicitZenRule(UserHandle user, String callingPkg, int callingUid,
NotificationManager.Policy policy) {
- if (!android.app.Flags.modesApi()) {
- Log.wtf(TAG, "applyGlobalPolicyAsImplicitZenRule called with flag off!");
- return;
- }
synchronized (mConfigLock) {
ZenModeConfig config = getConfigLocked(user);
if (config == null) {
@@ -772,10 +724,6 @@ public class ZenModeHelper {
*/
@Nullable
Policy getNotificationPolicyFromImplicitZenRule(UserHandle user, String callingPkg) {
- if (!android.app.Flags.modesApi()) {
- Log.wtf(TAG, "getNotificationPolicyFromImplicitZenRule called with flag off!");
- return getNotificationPolicy(user);
- }
synchronized (mConfigLock) {
ZenModeConfig config = getConfigLocked(user);
if (config == null) {
@@ -814,7 +762,6 @@ public class ZenModeHelper {
.appendPath(pkg)
.build();
rule.enabled = true;
- rule.modified = false;
rule.component = null;
rule.configurationActivity = null;
return rule;
@@ -918,15 +865,12 @@ public class ZenModeHelper {
private void maybePreserveRemovedRule(ZenModeConfig config, ZenRule ruleToRemove,
@ConfigOrigin int origin) {
- if (!Flags.modesApi()) {
- return;
- }
// If an app deletes a previously customized rule, keep it around to preserve
// the user's customization when/if it's recreated later.
// We don't try to preserve system-owned rules because their conditionIds (used as
// deletedRuleKey) are not stable. This is almost moot anyway because an app cannot
// delete a system-owned rule.
- if (origin == ORIGIN_APP && !ruleToRemove.canBeUpdatedByApp()
+ if (origin == ORIGIN_APP && ruleToRemove.isUserModified()
&& !PACKAGE_ANDROID.equals(ruleToRemove.pkg)) {
String deletedKey = ZenModeConfig.deletedRuleKey(ruleToRemove);
if (deletedKey != null) {
@@ -952,7 +896,7 @@ public class ZenModeHelper {
if (rule == null || !canManageAutomaticZenRule(rule, callingUid)) {
return Condition.STATE_UNKNOWN;
}
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
return rule.isActive() ? STATE_TRUE : STATE_FALSE;
} else {
// Buggy, does not consider snoozing!
@@ -971,16 +915,9 @@ public class ZenModeHelper {
newConfig = config.copy();
ZenRule rule = newConfig.automaticRules.get(id);
- if (Flags.modesApi()) {
- if (rule != null && canManageAutomaticZenRule(rule, callingUid)) {
- setAutomaticZenRuleStateLocked(newConfig, Collections.singletonList(rule),
- condition, origin, "setAzrState: " + rule.id, callingUid);
- }
- } else {
- ArrayList<ZenRule> rules = new ArrayList<>();
- rules.add(rule); // rule may be null and throw NPE in the next method.
- setAutomaticZenRuleStateLocked(newConfig, rules, condition, origin,
- "setAzrState: " + (rule != null ? rule.id : "null!"), callingUid);
+ if (rule != null && canManageAutomaticZenRule(rule, callingUid)) {
+ setAutomaticZenRuleStateLocked(newConfig, Collections.singletonList(rule),
+ condition, origin, "setAzrState: " + rule.id, callingUid);
}
}
}
@@ -995,13 +932,12 @@ public class ZenModeHelper {
newConfig = config.copy();
List<ZenRule> matchingRules = findMatchingRules(newConfig, ruleConditionId, condition);
- if (Flags.modesApi()) {
- for (int i = matchingRules.size() - 1; i >= 0; i--) {
- if (!canManageAutomaticZenRule(matchingRules.get(i), callingUid)) {
- matchingRules.remove(i);
- }
+ for (int i = matchingRules.size() - 1; i >= 0; i--) {
+ if (!canManageAutomaticZenRule(matchingRules.get(i), callingUid)) {
+ matchingRules.remove(i);
}
}
+
setAutomaticZenRuleStateLocked(newConfig, matchingRules, condition, origin,
"setAzrStateFromCps: " + ruleConditionId, callingUid);
}
@@ -1013,7 +949,7 @@ public class ZenModeHelper {
if (rules == null || rules.isEmpty()) return;
if (!Flags.modesUi()) {
- if (Flags.modesApi() && condition.source == SOURCE_USER_ACTION) {
+ if (condition.source == SOURCE_USER_ACTION) {
origin = ORIGIN_USER_IN_APP; // Although coming from app, it's actually from user.
}
}
@@ -1026,7 +962,7 @@ public class ZenModeHelper {
private static void applyConditionAndReconsiderOverride(ZenRule rule, Condition condition,
int origin) {
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
if (isImplicitRuleId(rule.id)) {
// Implicit rules do not use overrides, and always apply conditions directly.
// This is compatible with the previous behavior (where the package set the
@@ -1173,8 +1109,7 @@ public class ZenModeHelper {
// if default rule wasn't user-modified use localized name
// instead of previous system name
if (currRule != null
- && !currRule.modified
- && (currRule.zenPolicyUserModifiedFields & AutomaticZenRule.FIELD_NAME) == 0
+ && (currRule.userModifiedFields & AutomaticZenRule.FIELD_NAME) == 0
&& !defaultRule.name.equals(currRule.name)) {
if (DEBUG) {
Slog.d(TAG, "Locale change - updating default zen rule name "
@@ -1184,7 +1119,7 @@ public class ZenModeHelper {
updated = true;
}
}
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
for (ZenRule rule : newConfig.automaticRules.values()) {
if (SystemZenRules.isSystemOwnedRule(rule)) {
updated |= SystemZenRules.updateTriggerDescription(mContext, rule);
@@ -1256,172 +1191,145 @@ public class ZenModeHelper {
@GuardedBy("mConfigLock")
private boolean populateZenRule(String pkg, AutomaticZenRule azr, ZenModeConfig config,
ZenRule rule, @ConfigOrigin int origin, boolean isNew) {
- if (Flags.modesApi()) {
- boolean modified = false;
- // These values can always be edited by the app, so we apply changes immediately.
- if (isNew) {
- rule.id = ZenModeConfig.newRuleId();
- rule.creationTime = mClock.millis();
- rule.component = azr.getOwner();
- rule.pkg = pkg;
- modified = true;
- }
- // Allow updating the CPS backing system rules (e.g. for custom manual -> schedule)
- if (Flags.modesUi()
- && (origin == ORIGIN_SYSTEM || origin == ORIGIN_USER_IN_SYSTEMUI)
- && Objects.equals(rule.pkg, SystemZenRules.PACKAGE_ANDROID)
- && !Objects.equals(rule.component, azr.getOwner())) {
- rule.component = azr.getOwner();
- modified = true;
- }
+ boolean modified = false;
+ // These values can always be edited by the app, so we apply changes immediately.
+ if (isNew) {
+ rule.id = ZenModeConfig.newRuleId();
+ rule.creationTime = mClock.millis();
+ rule.component = azr.getOwner();
+ rule.pkg = pkg;
+ modified = true;
+ }
- if (Flags.modesUi()) {
- if (!azr.isEnabled() && (isNew || rule.enabled)) {
- // Creating a rule as disabled, or disabling a previously enabled rule.
- // Record whodunit.
- rule.disabledOrigin = origin;
- } else if (azr.isEnabled()) {
- // Enabling or previously enabled. Clear disabler.
- rule.disabledOrigin = ORIGIN_UNKNOWN;
- }
- }
+ // Allow updating the CPS backing system rules (e.g. for custom manual -> schedule)
+ if (Flags.modesUi()
+ && (origin == ORIGIN_SYSTEM || origin == ORIGIN_USER_IN_SYSTEMUI)
+ && Objects.equals(rule.pkg, SystemZenRules.PACKAGE_ANDROID)
+ && !Objects.equals(rule.component, azr.getOwner())) {
+ rule.component = azr.getOwner();
+ modified = true;
+ }
- if (!Objects.equals(rule.conditionId, azr.getConditionId())) {
- rule.conditionId = azr.getConditionId();
- modified = true;
- }
- // This can be removed when {@link Flags#modesUi} is fully ramped up
- final boolean isWatch =
- mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
- boolean shouldPreserveCondition =
- Flags.modesApi()
- && (Flags.modesUi() || isWatch)
- && !isNew
- && origin == ORIGIN_USER_IN_SYSTEMUI
- && rule.enabled == azr.isEnabled()
- && rule.conditionId != null
- && rule.condition != null
- && rule.conditionId.equals(rule.condition.id);
- if (!shouldPreserveCondition) {
- // Do not update 'modified'. If only this changes we treat it as a no-op updateAZR.
- rule.condition = null;
- }
-
- if (rule.enabled != azr.isEnabled()) {
- rule.enabled = azr.isEnabled();
- rule.resetConditionOverride();
- modified = true;
- }
- if (!Objects.equals(rule.configurationActivity, azr.getConfigurationActivity())) {
- rule.configurationActivity = azr.getConfigurationActivity();
- modified = true;
- }
- if (rule.allowManualInvocation != azr.isManualInvocationAllowed()) {
- rule.allowManualInvocation = azr.isManualInvocationAllowed();
- modified = true;
- }
- if (!Flags.modesUi()) {
- String iconResName = drawableResIdToResName(rule.pkg, azr.getIconResId());
- if (!Objects.equals(rule.iconResName, iconResName)) {
- rule.iconResName = iconResName;
- modified = true;
- }
- }
- if (!Objects.equals(rule.triggerDescription, azr.getTriggerDescription())) {
- rule.triggerDescription = azr.getTriggerDescription();
- modified = true;
+ if (Flags.modesUi()) {
+ if (!azr.isEnabled() && (isNew || rule.enabled)) {
+ // Creating a rule as disabled, or disabling a previously enabled rule.
+ // Record whodunit.
+ rule.disabledOrigin = origin;
+ } else if (azr.isEnabled()) {
+ // Enabling or previously enabled. Clear disabler.
+ rule.disabledOrigin = ORIGIN_UNKNOWN;
}
- if (rule.type != azr.getType()) {
- rule.type = azr.getType();
+ }
+
+ if (!Objects.equals(rule.conditionId, azr.getConditionId())) {
+ rule.conditionId = azr.getConditionId();
+ modified = true;
+ }
+ // This can be removed when {@link Flags#modesUi} is fully ramped up
+ final boolean isWatch =
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ boolean shouldPreserveCondition =
+ (Flags.modesUi() || isWatch)
+ && !isNew
+ && origin == ORIGIN_USER_IN_SYSTEMUI
+ && rule.enabled == azr.isEnabled()
+ && rule.conditionId != null
+ && rule.condition != null
+ && rule.conditionId.equals(rule.condition.id);
+ if (!shouldPreserveCondition) {
+ // Do not update 'modified'. If only this changes we treat it as a no-op updateAZR.
+ rule.condition = null;
+ }
+
+ if (rule.enabled != azr.isEnabled()) {
+ rule.enabled = azr.isEnabled();
+ rule.resetConditionOverride();
+ modified = true;
+ }
+ if (!Objects.equals(rule.configurationActivity, azr.getConfigurationActivity())) {
+ rule.configurationActivity = azr.getConfigurationActivity();
+ modified = true;
+ }
+ if (rule.allowManualInvocation != azr.isManualInvocationAllowed()) {
+ rule.allowManualInvocation = azr.isManualInvocationAllowed();
+ modified = true;
+ }
+ if (!Flags.modesUi()) {
+ String iconResName = drawableResIdToResName(rule.pkg, azr.getIconResId());
+ if (!Objects.equals(rule.iconResName, iconResName)) {
+ rule.iconResName = iconResName;
modified = true;
}
- // TODO: b/310620812 - Remove this once FLAG_MODES_API is inlined.
- rule.modified = azr.isModified();
+ }
+ if (!Objects.equals(rule.triggerDescription, azr.getTriggerDescription())) {
+ rule.triggerDescription = azr.getTriggerDescription();
+ modified = true;
+ }
+ if (rule.type != azr.getType()) {
+ rule.type = azr.getType();
+ modified = true;
+ }
- // Name is treated differently than other values:
- // App is allowed to update name if the name was not modified by the user (even if
- // other values have been modified). In this way, if the locale of an app changes,
- // i18n of the rule name can still occur even if the user has customized the rule
- // contents.
- String previousName = rule.name;
- if (isNew || doesOriginAlwaysUpdateValues(origin)
- || (rule.userModifiedFields & AutomaticZenRule.FIELD_NAME) == 0) {
- rule.name = azr.getName();
- modified |= !Objects.equals(rule.name, previousName);
- }
+ // Name is treated differently than other values:
+ // App is allowed to update name if the name was not modified by the user (even if
+ // other values have been modified). In this way, if the locale of an app changes,
+ // i18n of the rule name can still occur even if the user has customized the rule
+ // contents.
+ String previousName = rule.name;
+ if (isNew || doesOriginAlwaysUpdateValues(origin)
+ || (rule.userModifiedFields & AutomaticZenRule.FIELD_NAME) == 0) {
+ rule.name = azr.getName();
+ modified |= !Objects.equals(rule.name, previousName);
+ }
- // For the remaining values, rules can always have all values updated if:
- // * the rule is newly added, or
- // * the request comes from an origin that can always update values, like the user, or
- // * the rule has not yet been user modified, and thus can be updated by the app.
- boolean updateValues = isNew || doesOriginAlwaysUpdateValues(origin)
- || rule.canBeUpdatedByApp();
+ // For the remaining values, rules can always have all values updated if:
+ // * the rule is newly added, or
+ // * the request comes from an origin that can always update values, like the user, or
+ // * the rule has not yet been user modified, and thus can be updated by the app.
+ boolean updateValues = isNew || doesOriginAlwaysUpdateValues(origin)
+ || !rule.isUserModified();
- // For all other values, if updates are not allowed, we discard the update.
- if (!updateValues) {
- return modified;
- }
+ // For all other values, if updates are not allowed, we discard the update.
+ if (!updateValues) {
+ return modified;
+ }
- // Updates the bitmasks if the origin of the change is the user.
- boolean updateBitmask = (origin == ORIGIN_USER_IN_SYSTEMUI);
+ // Updates the bitmasks if the origin of the change is the user.
+ boolean updateBitmask = (origin == ORIGIN_USER_IN_SYSTEMUI);
- if (updateBitmask && !TextUtils.equals(previousName, azr.getName())) {
- rule.userModifiedFields |= AutomaticZenRule.FIELD_NAME;
+ if (updateBitmask && !TextUtils.equals(previousName, azr.getName())) {
+ rule.userModifiedFields |= AutomaticZenRule.FIELD_NAME;
+ }
+ int newZenMode = NotificationManager.zenModeFromInterruptionFilter(
+ azr.getInterruptionFilter(), Global.ZEN_MODE_OFF);
+ if (rule.zenMode != newZenMode) {
+ rule.zenMode = newZenMode;
+ if (updateBitmask) {
+ rule.userModifiedFields |= AutomaticZenRule.FIELD_INTERRUPTION_FILTER;
}
- int newZenMode = NotificationManager.zenModeFromInterruptionFilter(
- azr.getInterruptionFilter(), Global.ZEN_MODE_OFF);
- if (rule.zenMode != newZenMode) {
- rule.zenMode = newZenMode;
+ modified = true;
+ }
+
+ if (Flags.modesUi()) {
+ String iconResName = drawableResIdToResName(rule.pkg, azr.getIconResId());
+ if (!Objects.equals(rule.iconResName, iconResName)) {
+ rule.iconResName = iconResName;
if (updateBitmask) {
- rule.userModifiedFields |= AutomaticZenRule.FIELD_INTERRUPTION_FILTER;
+ rule.userModifiedFields |= AutomaticZenRule.FIELD_ICON;
}
modified = true;
}
+ }
- if (Flags.modesUi()) {
- String iconResName = drawableResIdToResName(rule.pkg, azr.getIconResId());
- if (!Objects.equals(rule.iconResName, iconResName)) {
- rule.iconResName = iconResName;
- if (updateBitmask) {
- rule.userModifiedFields |= AutomaticZenRule.FIELD_ICON;
- }
- modified = true;
- }
- }
-
- // Updates the bitmask and values for all policy fields, based on the origin.
- modified |= updatePolicy(config, rule, azr.getZenPolicy(), updateBitmask, isNew);
+ // Updates the bitmask and values for all policy fields, based on the origin.
+ modified |= updatePolicy(config, rule, azr.getZenPolicy(), updateBitmask, isNew);
- // Updates the bitmask and values for all device effect fields, based on the origin.
- modified |= updateZenDeviceEffects(rule, azr.getDeviceEffects(),
- origin == ORIGIN_APP, updateBitmask);
+ // Updates the bitmask and values for all device effect fields, based on the origin.
+ modified |= updateZenDeviceEffects(rule, azr.getDeviceEffects(),
+ origin == ORIGIN_APP, updateBitmask);
- return modified;
- } else {
- if (rule.enabled != azr.isEnabled()) {
- rule.resetConditionOverride();
- }
- rule.name = azr.getName();
- rule.condition = null;
- rule.conditionId = azr.getConditionId();
- rule.enabled = azr.isEnabled();
- rule.modified = azr.isModified();
- rule.zenPolicy = azr.getZenPolicy();
- rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
- azr.getInterruptionFilter(), Global.ZEN_MODE_OFF);
- rule.configurationActivity = azr.getConfigurationActivity();
-
- if (isNew) {
- rule.id = ZenModeConfig.newRuleId();
- rule.creationTime = System.currentTimeMillis();
- rule.component = azr.getOwner();
- rule.pkg = pkg;
- }
-
- // Only the MODES_API path cares about the result, so just return whatever here.
- return true;
- }
+ return modified;
}
/**
@@ -1629,32 +1537,21 @@ public class ZenModeHelper {
}
private AutomaticZenRule zenRuleToAutomaticZenRule(ZenRule rule) {
- AutomaticZenRule azr;
- if (Flags.modesApi()) {
- azr = new AutomaticZenRule.Builder(rule.name, rule.conditionId)
- .setManualInvocationAllowed(rule.allowManualInvocation)
- .setPackage(rule.pkg)
- .setCreationTime(rule.creationTime)
- .setIconResId(drawableResNameToResId(rule.pkg, rule.iconResName))
- .setType(rule.type)
- .setZenPolicy(rule.zenPolicy)
- .setDeviceEffects(rule.zenDeviceEffects)
- .setEnabled(rule.enabled)
- .setInterruptionFilter(
- NotificationManager.zenModeToInterruptionFilter(rule.zenMode))
- .setOwner(rule.component)
- .setConfigurationActivity(rule.configurationActivity)
- .setTriggerDescription(rule.triggerDescription)
- .build();
- } else {
- azr = new AutomaticZenRule(rule.name, rule.component,
- rule.configurationActivity,
- rule.conditionId, rule.zenPolicy,
- NotificationManager.zenModeToInterruptionFilter(rule.zenMode),
- rule.enabled, rule.creationTime);
- azr.setPackageName(rule.pkg);
- }
- return azr;
+ return new AutomaticZenRule.Builder(rule.name, rule.conditionId)
+ .setManualInvocationAllowed(rule.allowManualInvocation)
+ .setPackage(rule.pkg)
+ .setCreationTime(rule.creationTime)
+ .setIconResId(drawableResNameToResId(rule.pkg, rule.iconResName))
+ .setType(rule.type)
+ .setZenPolicy(rule.zenPolicy)
+ .setDeviceEffects(rule.zenDeviceEffects)
+ .setEnabled(rule.enabled)
+ .setInterruptionFilter(
+ NotificationManager.zenModeToInterruptionFilter(rule.zenMode))
+ .setOwner(rule.component)
+ .setConfigurationActivity(rule.configurationActivity)
+ .setTriggerDescription(rule.triggerDescription)
+ .build();
}
// Update only the hasPriorityChannels state (aka areChannelsBypassingDnd) without modifying
@@ -1669,12 +1566,12 @@ public class ZenModeHelper {
if (config == null) return;
// If it already matches, do nothing
- if (config.areChannelsBypassingDnd == hasPriorityChannels) {
+ if (config.hasPriorityChannels == hasPriorityChannels) {
return;
}
ZenModeConfig newConfig = config.copy();
- newConfig.areChannelsBypassingDnd = hasPriorityChannels;
+ newConfig.hasPriorityChannels = hasPriorityChannels;
// The updated calculation of whether there are priority channels is always done by
// the system, even if the event causing the calculation had a different origin.
setConfigLocked(newConfig, null, ORIGIN_SYSTEM, "updateHasPriorityChannels",
@@ -1754,9 +1651,7 @@ public class ZenModeHelper {
newRule.zenMode = zenMode;
newRule.conditionId = conditionId;
newRule.enabler = caller;
- if (Flags.modesApi()) {
- newRule.allowManualInvocation = true;
- }
+ newRule.allowManualInvocation = true;
newConfig.manualRule = newRule;
}
}
@@ -1849,7 +1744,7 @@ public class ZenModeHelper {
boolean hasDefaultRules = config.automaticRules.containsAll(
ZenModeConfig.getDefaultRuleIds());
- long time = Flags.modesApi() ? mClock.millis() : System.currentTimeMillis();
+ long time = mClock.millis();
if (config.automaticRules != null && config.automaticRules.size() > 0) {
for (ZenRule automaticRule : config.automaticRules.values()) {
if (forRestore) {
@@ -1863,7 +1758,7 @@ public class ZenModeHelper {
// Upon upgrading to a version with modes_api enabled, keep all behaviors of
// rules with null ZenPolicies explicitly as a copy of the global policy.
- if (Flags.modesApi() && config.version < ZenModeConfig.XML_VERSION_MODES_API) {
+ if (config.version < ZenModeConfig.XML_VERSION_MODES_API) {
// Keep the manual ("global") policy that from config.
ZenPolicy manualRulePolicy = config.getZenPolicy();
if (automaticRule.zenPolicy == null) {
@@ -1877,8 +1772,7 @@ public class ZenModeHelper {
}
}
- if (Flags.modesApi() && Flags.modesUi()
- && config.version < ZenModeConfig.XML_VERSION_MODES_UI) {
+ if (Flags.modesUi() && config.version < ZenModeConfig.XML_VERSION_MODES_UI) {
// Clear icons from implicit rules. App icons are not suitable for some
// surfaces, so juse use a default (the user can select a different one).
if (ZenModeConfig.isImplicitRuleId(automaticRule.id)) {
@@ -1904,11 +1798,11 @@ public class ZenModeHelper {
reason += ", reset to default rules";
}
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
SystemZenRules.maybeUpgradeRules(mContext, config);
}
- if (Flags.modesApi() && forRestore) {
+ if (forRestore) {
// Note: forBackup doesn't write deletedRules, but just in case.
config.deletedRules.clear();
}
@@ -1995,7 +1889,7 @@ public class ZenModeHelper {
if (config == null) return;
final ZenModeConfig newConfig = config.copy();
- if (Flags.modesApi() && !Flags.modesUi()) {
+ if (!Flags.modesUi()) {
// Fix for b/337193321 -- propagate changes to notificationPolicy to rules where
// the user cannot edit zen policy to emulate the previous "inheritance".
ZenPolicy previousPolicy = ZenAdapters.notificationPolicyToZenPolicy(
@@ -2026,6 +1920,7 @@ public class ZenModeHelper {
* <ul>
* <li>Rule instances whose owner is not installed.
* <li>Deleted rules that were deleted more than 30 days ago.
+ * <li>Implicit rules that haven't been used in 30 days (and have not been customized).
* </ul>
*/
private void cleanUpZenRules() {
@@ -2034,17 +1929,20 @@ public class ZenModeHelper {
final ZenModeConfig newConfig = mConfig.copy();
deleteRulesWithoutOwner(newConfig.automaticRules);
- if (Flags.modesApi()) {
- deleteRulesWithoutOwner(newConfig.deletedRules);
- for (int i = newConfig.deletedRules.size() - 1; i >= 0; i--) {
- ZenRule deletedRule = newConfig.deletedRules.valueAt(i);
- if (deletedRule.deletionInstant == null
- || deletedRule.deletionInstant.isBefore(keptRuleThreshold)) {
- newConfig.deletedRules.removeAt(i);
- }
+ deleteRulesWithoutOwner(newConfig.deletedRules);
+
+ for (int i = newConfig.deletedRules.size() - 1; i >= 0; i--) {
+ ZenRule deletedRule = newConfig.deletedRules.valueAt(i);
+ if (deletedRule.deletionInstant == null
+ || deletedRule.deletionInstant.isBefore(keptRuleThreshold)) {
+ newConfig.deletedRules.removeAt(i);
}
}
+ if (Flags.modesUi() && Flags.modesCleanupImplicit()) {
+ deleteUnusedImplicitRules(newConfig.automaticRules);
+ }
+
if (!newConfig.equals(mConfig)) {
setConfigLocked(newConfig, null, ORIGIN_SYSTEM,
"cleanUpZenRules", Process.SYSTEM_UID);
@@ -2053,7 +1951,7 @@ public class ZenModeHelper {
}
private void deleteRulesWithoutOwner(ArrayMap<String, ZenRule> ruleList) {
- long currentTime = Flags.modesApi() ? mClock.millis() : System.currentTimeMillis();
+ long currentTime = mClock.millis();
if (ruleList != null) {
for (int i = ruleList.size() - 1; i >= 0; i--) {
ZenRule rule = ruleList.valueAt(i);
@@ -2070,6 +1968,29 @@ public class ZenModeHelper {
}
}
+ private void deleteUnusedImplicitRules(ArrayMap<String, ZenRule> ruleList) {
+ if (ruleList == null) {
+ return;
+ }
+ Instant deleteIfUnusedSince = mClock.instant().minus(IMPLICIT_RULE_KEPT_FOR);
+
+ for (int i = ruleList.size() - 1; i >= 0; i--) {
+ ZenRule rule = ruleList.valueAt(i);
+ if (isImplicitRuleId(rule.id) && !rule.isUserModified()) {
+ if (rule.lastActivation == null) {
+ // This rule existed before we started tracking activation time. It *might* be
+ // in use. Set lastActivation=now so it has some time (IMPLICIT_RULE_KEPT_FOR)
+ // before being removed if truly unused.
+ rule.lastActivation = mClock.instant();
+ }
+
+ if (rule.lastActivation.isBefore(deleteIfUnusedSince)) {
+ ruleList.removeAt(i);
+ }
+ }
+ }
+ }
+
/**
* @return a copy of the zen mode configuration
*/
@@ -2188,7 +2109,7 @@ public class ZenModeHelper {
mZenMode, mConfig, mConsolidatedPolicy);
if (!config.equals(mConfig)) {
// Schedule broadcasts. Cannot be sent during boot, though.
- if (Flags.modesApi() && origin != ORIGIN_INIT) {
+ if (origin != ORIGIN_INIT) {
for (ZenRule rule : config.automaticRules.values()) {
ZenRule original = mConfig.automaticRules.get(rule.id);
if (original != null) {
@@ -2204,6 +2125,20 @@ public class ZenModeHelper {
}
}
+ // Update last activation for rules that are being activated.
+ if (Flags.modesUi() && Flags.modesCleanupImplicit()) {
+ Instant now = mClock.instant();
+ if (!mConfig.isManualActive() && config.isManualActive()) {
+ config.manualRule.lastActivation = now;
+ }
+ for (ZenRule rule : config.automaticRules.values()) {
+ ZenRule previousRule = mConfig.automaticRules.get(rule.id);
+ if (rule.isActive() && (previousRule == null || !previousRule.isActive())) {
+ rule.lastActivation = now;
+ }
+ }
+ }
+
mConfig = config;
dispatchOnConfigChanged();
updateAndApplyConsolidatedPolicyAndDeviceEffects(origin, reason);
@@ -2295,7 +2230,7 @@ public class ZenModeHelper {
private void applyCustomPolicy(ZenModeConfig config, ZenPolicy policy, ZenRule rule,
boolean useManualConfig) {
if (rule.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
policy.apply(ZenPolicy.getBasePolicyInterruptionFilterNone());
} else {
policy.apply(new ZenPolicy.Builder()
@@ -2304,7 +2239,7 @@ public class ZenModeHelper {
.build());
}
} else if (rule.zenMode == Global.ZEN_MODE_ALARMS) {
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
policy.apply(ZenPolicy.getBasePolicyInterruptionFilterAlarms());
} else {
policy.apply(new ZenPolicy.Builder()
@@ -2317,22 +2252,17 @@ public class ZenModeHelper {
} else if (rule.zenPolicy != null) {
policy.apply(rule.zenPolicy);
} else {
- if (Flags.modesApi()) {
- if (useManualConfig) {
- // manual rule is configured using the settings stored directly in ZenModeConfig
- policy.apply(config.getZenPolicy());
- } else {
- // under modes_api flag, an active automatic rule with no specified policy
- // inherits the device default settings as stored in mDefaultConfig. While the
- // rule's policy fields should be set upon creation, this is a fallback to
- // catch any that may have fallen through the cracks.
- Log.wtf(TAG, "active automatic rule found with no specified policy: " + rule);
- policy.apply(Flags.modesUi()
- ? mDefaultConfig.getZenPolicy() : config.getZenPolicy());
- }
- } else {
- // active rule with no specified policy inherits the manual rule config settings
+ if (useManualConfig) {
+ // manual rule is configured using the settings stored directly in ZenModeConfig
policy.apply(config.getZenPolicy());
+ } else {
+ // An active automatic rule with no specified policy inherits the device default
+ // settings as stored in mDefaultConfig. While the rule's policy fields should be
+ // set upon creation, this is a fallback to catch any that may have fallen through
+ // the cracks.
+ Log.wtf(TAG, "active automatic rule found with no specified policy: " + rule);
+ policy.apply(Flags.modesUi()
+ ? mDefaultConfig.getZenPolicy() : config.getZenPolicy());
}
}
}
@@ -2346,9 +2276,7 @@ public class ZenModeHelper {
ZenDeviceEffects.Builder deviceEffectsBuilder = new ZenDeviceEffects.Builder();
if (mConfig.isManualActive()) {
applyCustomPolicy(mConfig, policy, mConfig.manualRule, true);
- if (Flags.modesApi()) {
- deviceEffectsBuilder.add(mConfig.manualRule.zenDeviceEffects);
- }
+ deviceEffectsBuilder.add(mConfig.manualRule.zenDeviceEffects);
}
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
@@ -2356,12 +2284,10 @@ public class ZenModeHelper {
// Active rules with INTERRUPTION_FILTER_ALL are not included in consolidated
// policy. This is relevant in case some other active rule has a more
// restrictive INTERRUPTION_FILTER but a more lenient ZenPolicy!
- if (!Flags.modesApi() || automaticRule.zenMode != Global.ZEN_MODE_OFF) {
+ if (automaticRule.zenMode != Global.ZEN_MODE_OFF) {
applyCustomPolicy(mConfig, policy, automaticRule, false);
}
- if (Flags.modesApi()) {
- deviceEffectsBuilder.add(automaticRule.zenDeviceEffects);
- }
+ deviceEffectsBuilder.add(automaticRule.zenDeviceEffects);
}
}
@@ -2380,40 +2306,35 @@ public class ZenModeHelper {
ZenLog.traceSetConsolidatedZenPolicy(mConsolidatedPolicy, reason);
}
- if (Flags.modesApi()) {
- // Prevent other rules from applying grayscale if Driving is active (but allow it
- // if _Driving itself_ wants grayscale).
- if (Flags.modesUi() && preventZenDeviceEffectsWhileDriving()) {
- boolean hasActiveDriving = false;
- boolean hasActiveDrivingWithGrayscale = false;
- for (ZenRule rule : mConfig.automaticRules.values()) {
- if (rule.isActive() && rule.type == TYPE_DRIVING) {
- hasActiveDriving = true;
- if (rule.zenDeviceEffects != null
- && rule.zenDeviceEffects.shouldDisplayGrayscale()) {
- hasActiveDrivingWithGrayscale = true;
- break; // Further rules won't affect decision.
- }
+ // Prevent other rules from applying grayscale if Driving is active (but allow it
+ // if _Driving itself_ wants grayscale).
+ if (Flags.modesUi() && preventZenDeviceEffectsWhileDriving()) {
+ boolean hasActiveDriving = false;
+ boolean hasActiveDrivingWithGrayscale = false;
+ for (ZenRule rule : mConfig.automaticRules.values()) {
+ if (rule.isActive() && rule.type == TYPE_DRIVING) {
+ hasActiveDriving = true;
+ if (rule.zenDeviceEffects != null
+ && rule.zenDeviceEffects.shouldDisplayGrayscale()) {
+ hasActiveDrivingWithGrayscale = true;
+ break; // Further rules won't affect decision.
}
}
- if (hasActiveDriving && !hasActiveDrivingWithGrayscale) {
- deviceEffectsBuilder.setShouldDisplayGrayscale(false);
- }
}
-
- ZenDeviceEffects deviceEffects = deviceEffectsBuilder.build();
- if (!deviceEffects.equals(mConsolidatedDeviceEffects)) {
- mConsolidatedDeviceEffects = deviceEffects;
- mHandler.postApplyDeviceEffects(origin);
+ if (hasActiveDriving && !hasActiveDrivingWithGrayscale) {
+ deviceEffectsBuilder.setShouldDisplayGrayscale(false);
}
}
+
+ ZenDeviceEffects deviceEffects = deviceEffectsBuilder.build();
+ if (!deviceEffects.equals(mConsolidatedDeviceEffects)) {
+ mConsolidatedDeviceEffects = deviceEffects;
+ mHandler.postApplyDeviceEffects(origin);
+ }
}
}
private void applyConsolidatedDeviceEffects(@ConfigOrigin int source) {
- if (!Flags.modesApi()) {
- return;
- }
DeviceEffectsApplier applier;
ZenDeviceEffects effects;
synchronized (mConfigLock) {
@@ -2434,10 +2355,8 @@ public class ZenModeHelper {
* to the current locale.
*/
private static void updateDefaultConfig(Context context, ZenModeConfig defaultConfig) {
- if (Flags.modesApi()) {
- updateDefaultAutomaticRulePolicies(defaultConfig);
- }
- if (Flags.modesApi() && Flags.modesUi()) {
+ updateDefaultAutomaticRulePolicies(defaultConfig);
+ if (Flags.modesUi()) {
SystemZenRules.maybeUpgradeRules(context, defaultConfig);
}
updateRuleStringsForCurrentLocale(context, defaultConfig);
@@ -2453,7 +2372,7 @@ public class ZenModeHelper {
rule.name = context.getResources()
.getString(R.string.zen_mode_default_every_night_name);
}
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
SystemZenRules.updateTriggerDescription(context, rule);
}
}
@@ -2462,10 +2381,6 @@ public class ZenModeHelper {
// Updates the policies in the default automatic rules (provided via default XML config) to
// be fully filled in default values.
private static void updateDefaultAutomaticRulePolicies(ZenModeConfig defaultConfig) {
- if (!Flags.modesApi()) {
- // Should be checked before calling, but just in case.
- return;
- }
ZenPolicy defaultPolicy = defaultConfig.getZenPolicy();
for (ZenRule rule : defaultConfig.automaticRules.values()) {
if (ZenModeConfig.getDefaultRuleIds().contains(rule.id) && rule.zenPolicy == null) {
@@ -2611,6 +2526,7 @@ public class ZenModeHelper {
}
}
+ // TODO: b/368247671 - Delete this method AND default_zen_mode_config.xml when inlining modes_ui
private ZenModeConfig readDefaultConfig(Resources resources) {
XmlResourceParser parser = null;
try {
@@ -2649,7 +2565,7 @@ public class ZenModeHelper {
events.add(FrameworkStatsLog.buildStatsEvent(DND_MODE_RULE,
/* optional int32 user = 1 */ user,
/* optional bool enabled = 2 */ config.isManualActive(),
- /* optional bool channels_bypassing = 3 */ config.areChannelsBypassingDnd,
+ /* optional bool channels_bypassing = 3 */ config.hasPriorityChannels,
/* optional LoggedZenMode zen_mode = 4 */ ROOT_CONFIG,
/* optional string id = 5 */ "", // empty for root config
/* optional int32 uid = 6 */ Process.SYSTEM_UID, // system owns root config
@@ -2924,9 +2840,6 @@ public class ZenModeHelper {
* ({@link #addAutomaticZenRule}, {@link #removeAutomaticZenRule}, etc, makes sense.
*/
private static void checkManageRuleOrigin(String method, @ConfigOrigin int origin) {
- if (!Flags.modesApi()) {
- return;
- }
checkArgument(origin == ORIGIN_APP || origin == ORIGIN_SYSTEM
|| origin == ORIGIN_USER_IN_SYSTEMUI,
"Expected one of ORIGIN_APP, ORIGIN_SYSTEM, or "
@@ -2939,9 +2852,6 @@ public class ZenModeHelper {
* {@link #setAutomaticZenRuleStateFromConditionProvider} makes sense.
*/
private static void checkSetRuleStateOrigin(String method, @ConfigOrigin int origin) {
- if (!Flags.modesApi()) {
- return;
- }
checkArgument(origin == ORIGIN_APP || origin == ORIGIN_USER_IN_APP
|| origin == ORIGIN_SYSTEM || origin == ORIGIN_USER_IN_SYSTEMUI,
"Expected one of ORIGIN_APP, ORIGIN_USER_IN_APP, ORIGIN_SYSTEM, or "
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index 048f2b6b0cbc..76cd5c88b388 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -210,3 +210,10 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "managed_services_concurrent_multiuser"
+ namespace: "systemui"
+ description: "Enables ManagedServices to support Concurrent multi user environment"
+ bug: "380297485"
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
index d538bb876b64..c3af578de369 100644
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
@@ -176,16 +176,13 @@ public class BackgroundInstallControlService extends SystemService {
if (Flags.bicClient()) {
mService.enforceCallerPermissions();
}
- if (!Build.IS_DEBUGGABLE) {
- return mService.getBackgroundInstalledPackages(flags, userId);
- }
// The debug.transparency.bg-install-apps (only works for debuggable builds)
// is used to set mock list of background installed apps for testing.
// The list of apps' names is delimited by ",".
// TODO: Remove after migrating test to new background install method using
// {@link BackgroundInstallControlCallbackHelperTest}.installPackage b/310983905
String propertyString = SystemProperties.get("debug.transparency.bg-install-apps");
- if (TextUtils.isEmpty(propertyString)) {
+ if (TextUtils.isEmpty(propertyString) || !Build.IS_DEBUGGABLE) {
return mService.getBackgroundInstalledPackages(flags, userId);
} else {
return mService.getMockBackgroundInstalledPackages(propertyString);
@@ -219,10 +216,27 @@ public class BackgroundInstallControlService extends SystemService {
PackageManager.PackageInfoFlags.of(flags), userId);
initBackgroundInstalledPackages();
+ if(Build.IS_DEBUGGABLE) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Tracked background installed package size: ")
+ .append(mBackgroundInstalledPackages.size())
+ .append("\n");
+ for (int i = 0; i < mBackgroundInstalledPackages.size(); ++i) {
+ int installingUserId = mBackgroundInstalledPackages.keyAt(i);
+ mBackgroundInstalledPackages.get(installingUserId).forEach(pkgName ->
+ sb.append("userId: ").append(installingUserId)
+ .append(", name: ").append(pkgName).append("\n"));
+ }
+ Slog.d(TAG, "Tracked background installed package: " + sb.toString());
+ }
+
ListIterator<PackageInfo> iter = packages.listIterator();
while (iter.hasNext()) {
String packageName = iter.next().packageName;
if (!mBackgroundInstalledPackages.contains(userId, packageName)) {
+ if(Build.IS_DEBUGGABLE) {
+ Slog.d(TAG, packageName + " is not tracked, removing");
+ }
iter.remove();
}
}
@@ -284,6 +298,9 @@ public class BackgroundInstallControlService extends SystemService {
}
void handlePackageAdd(String packageName, int userId) {
+ if(Build.IS_DEBUGGABLE) {
+ Slog.d(TAG, "handlePackageAdd: checking " + packageName);
+ }
ApplicationInfo appInfo = null;
try {
appInfo =
@@ -302,7 +319,7 @@ public class BackgroundInstallControlService extends SystemService {
installerPackageName = installInfo.getInstallingPackageName();
initiatingPackageName = installInfo.getInitiatingPackageName();
} catch (PackageManager.NameNotFoundException e) {
- Slog.w(TAG, "Package's installer not found " + packageName);
+ Slog.w(TAG, "Package's installer not found: " + packageName);
return;
}
@@ -314,6 +331,10 @@ public class BackgroundInstallControlService extends SystemService {
VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT,
userId)
!= PERMISSION_GRANTED) {
+ if(Build.IS_DEBUGGABLE) {
+ Slog.d(TAG, "handlePackageAdd " + packageName + ": installer doesn't "
+ + "have INSTALL_PACKAGES permission, skipping");
+ }
return;
}
@@ -324,6 +345,10 @@ public class BackgroundInstallControlService extends SystemService {
if (installedByAdb(initiatingPackageName)
|| wasForegroundInstallation(installerPackageName, userId, installTimestamp)) {
+ if(Build.IS_DEBUGGABLE) {
+ Slog.d(TAG, "handlePackageAdd " + packageName + ": is installed by ADB or was "
+ + "foreground installation, skipping");
+ }
return;
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 55d2508d085e..15688c0f7366 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -1021,7 +1021,7 @@ final class InstallPackageHelper {
*
* Failure at any phase will result in a full failure to install all packages.
*/
- void installPackagesTraced(List<InstallRequest> requests) {
+ void installPackagesTraced(List<InstallRequest> requests, MoveInfo moveInfo) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
boolean success = false;
final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
@@ -1049,10 +1049,37 @@ final class InstallPackageHelper {
} finally {
completeInstallProcess(requests, createdAppId, success);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ doPostInstall(requests, moveInfo);
releaseWakeLock(acquireTime, requests.size());
}
}
+ private void doPostInstall(List<InstallRequest> requests, MoveInfo moveInfo) {
+ for (InstallRequest request : requests) {
+ doPostInstallCleanUp(request, moveInfo);
+ }
+
+ for (InstallRequest request : requests) {
+ restoreAndPostInstall(request);
+ }
+ }
+
+ private void doPostInstallCleanUp(InstallRequest request, MoveInfo moveInfo) {
+ if (moveInfo != null) {
+ if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) {
+ mRemovePackageHelper.cleanUpForMoveInstall(moveInfo.mFromUuid,
+ moveInfo.mPackageName, moveInfo.mFromCodePath);
+ } else {
+ mRemovePackageHelper.cleanUpForMoveInstall(moveInfo.mToUuid,
+ moveInfo.mPackageName, moveInfo.mFromCodePath);
+ }
+ } else {
+ if (request.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) {
+ mRemovePackageHelper.removeCodePath(request.getCodeFile());
+ }
+ }
+ }
+
private long acquireWakeLock(int count) {
if (!mPm.isSystemReady()) {
return -1;
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index 6a2bf83ba368..3d8f2bbf4e7f 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -550,31 +550,11 @@ class InstallingSession {
cleanUpForFailedInstall(request);
}
}
- } else {
- mPm.installPackagesTraced(installRequests);
-
for (InstallRequest request : installRequests) {
- doPostInstall(request);
- }
- }
- for (InstallRequest request : installRequests) {
- mPm.restoreAndPostInstall(request);
- }
- }
-
- private void doPostInstall(InstallRequest request) {
- if (mMoveInfo != null) {
- if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) {
- mPm.cleanUpForMoveInstall(mMoveInfo.mFromUuid,
- mMoveInfo.mPackageName, mMoveInfo.mFromCodePath);
- } else {
- mPm.cleanUpForMoveInstall(mMoveInfo.mToUuid,
- mMoveInfo.mPackageName, mMoveInfo.mFromCodePath);
+ mPm.restoreAndPostInstall(request);
}
} else {
- if (request.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) {
- mPm.removeCodePath(request.getCodeFile());
- }
+ mPm.installPackagesTraced(installRequests, mMoveInfo);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8343935425cd..2464a291b4dd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8214,8 +8214,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return mInstallPackageHelper.enableCompressedPackage(stubPkg, stubPs);
}
- void installPackagesTraced(List<InstallRequest> requests) {
- mInstallPackageHelper.installPackagesTraced(requests);
+ void installPackagesTraced(List<InstallRequest> requests, MoveInfo moveInfo) {
+ mInstallPackageHelper.installPackagesTraced(requests, moveInfo);
}
void restoreAndPostInstall(InstallRequest request) {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 587447b8af26..9d7e9f53a1aa 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -92,6 +92,8 @@ public class KeyguardServiceDelegate {
public boolean bootCompleted;
public int screenState;
public int interactiveState;
+ boolean doKeyguardTimeoutRequested;
+ Bundle doKeyguardTimeoutRequestedOptions;
private void reset() {
// Assume keyguard is showing and secure until we know for sure. This is here in
@@ -225,6 +227,12 @@ public class KeyguardServiceDelegate {
if (mKeyguardState.dreaming) {
mKeyguardService.onDreamingStarted();
}
+ if (mKeyguardState.doKeyguardTimeoutRequested) {
+ mKeyguardService.doKeyguardTimeout(
+ mKeyguardState.doKeyguardTimeoutRequestedOptions);
+ mKeyguardState.doKeyguardTimeoutRequested = false;
+ mKeyguardState.doKeyguardTimeoutRequestedOptions = null;
+ }
}
@Override
@@ -410,6 +418,11 @@ public class KeyguardServiceDelegate {
public void doKeyguardTimeout(Bundle options) {
if (mKeyguardService != null) {
mKeyguardService.doKeyguardTimeout(options);
+ } else {
+ mKeyguardState.doKeyguardTimeoutRequested = true;
+ if (options != null) {
+ mKeyguardState.doKeyguardTimeoutRequestedOptions = options;
+ }
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8fae875eb29b..e3eced252d1f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3379,7 +3379,7 @@ public final class PowerManagerService extends SystemService
}
changed = sleepPowerGroupLocked(powerGroup, time,
PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE, Process.SYSTEM_UID);
- } else if (shouldNapAtBedTimeLocked()) {
+ } else if (shouldNapAtBedTimeLocked(powerGroup)) {
changed = dreamPowerGroupLocked(powerGroup, time,
Process.SYSTEM_UID, /* allowWake= */ false);
} else {
@@ -3395,7 +3395,10 @@ public final class PowerManagerService extends SystemService
* activity timeout has expired and it's bedtime.
*/
@GuardedBy("mLock")
- private boolean shouldNapAtBedTimeLocked() {
+ private boolean shouldNapAtBedTimeLocked(PowerGroup powerGroup) {
+ if (!powerGroup.supportsSandmanLocked()) {
+ return false;
+ }
return mDreamsActivateOnSleepSetting
|| (mDreamsActivateOnDockSetting
&& mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED)
@@ -3617,9 +3620,10 @@ public final class PowerManagerService extends SystemService
if (!mDreamsDisabledByAmbientModeSuppressionConfig) {
return;
}
+ final PowerGroup defaultPowerGroup = mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP);
if (!isSuppressed && mIsPowered && mDreamsSupportedConfig && mDreamsEnabledSetting
- && shouldNapAtBedTimeLocked() && isItBedTimeYetLocked(
- mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP))) {
+ && shouldNapAtBedTimeLocked(defaultPowerGroup)
+ && isItBedTimeYetLocked(defaultPowerGroup)) {
napInternal(SystemClock.uptimeMillis(), Process.SYSTEM_UID, /* allowWake= */ true);
} else if (isSuppressed) {
mDirty |= DIRTY_SETTINGS;
diff --git a/services/core/java/com/android/server/resources/ResourcesManagerShellCommand.java b/services/core/java/com/android/server/resources/ResourcesManagerShellCommand.java
index a75d110e3cd1..17739712d65a 100644
--- a/services/core/java/com/android/server/resources/ResourcesManagerShellCommand.java
+++ b/services/core/java/com/android/server/resources/ResourcesManagerShellCommand.java
@@ -88,6 +88,5 @@ public class ResourcesManagerShellCommand extends ShellCommand {
out.println(" Print this help text.");
out.println(" dump <PROCESS>");
out.println(" Dump the Resources objects in use as well as the history of Resources");
-
}
}
diff --git a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
index f060e4d11e82..82df310db9a4 100644
--- a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
+++ b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
@@ -303,7 +303,11 @@ class AttestationVerificationPeerDeviceVerifier {
if (mRevocationEnabled) {
// Checks Revocation Status List based on
// https://developer.android.com/training/articles/security-key-attestation#certificate_status
- mCertificateRevocationStatusManager.checkRevocationStatus(certificates);
+ // The first certificate is the leaf, which is generated at runtime with the attestation
+ // attributes such as the challenge. It is specific to this attestation instance and
+ // does not need to be checked for revocation.
+ mCertificateRevocationStatusManager.checkRevocationStatus(
+ new ArrayList<>(certificates.subList(1, certificates.size())));
}
}
diff --git a/services/core/java/com/android/server/security/CertificateRevocationStatusManager.java b/services/core/java/com/android/server/security/CertificateRevocationStatusManager.java
index d36d9f5f6636..4cd4b3b84910 100644
--- a/services/core/java/com/android/server/security/CertificateRevocationStatusManager.java
+++ b/services/core/java/com/android/server/security/CertificateRevocationStatusManager.java
@@ -42,6 +42,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.security.cert.CertPathValidatorException;
import java.security.cert.X509Certificate;
+import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
@@ -67,6 +68,8 @@ class CertificateRevocationStatusManager {
*/
@VisibleForTesting static final int MAX_DAYS_SINCE_LAST_CHECK = 30;
+ @VisibleForTesting static final int NUM_HOURS_BEFORE_NEXT_CHECK = 24;
+
/**
* The number of days since issue date for an intermediary certificate to be considered fresh
* and not require a revocation list check.
@@ -127,6 +130,17 @@ class CertificateRevocationStatusManager {
serialNumbers.add(serialNumber);
}
try {
+ if (isLastCheckedWithin(Duration.ofHours(NUM_HOURS_BEFORE_NEXT_CHECK), serialNumbers)) {
+ Slog.d(
+ TAG,
+ "All certificates have been checked for revocation recently. No need to"
+ + " check this time.");
+ return;
+ }
+ } catch (IOException ignored) {
+ // Proceed to check the revocation status
+ }
+ try {
JSONObject revocationList = fetchRemoteRevocationList();
Map<String, Boolean> areCertificatesRevoked = new HashMap<>();
for (String serialNumber : serialNumbers) {
@@ -151,25 +165,32 @@ class CertificateRevocationStatusManager {
serialNumbers.remove(serialNumber);
}
}
- Map<String, LocalDateTime> lastRevocationCheckData;
try {
- lastRevocationCheckData = getLastRevocationCheckData();
+ if (!isLastCheckedWithin(
+ Duration.ofDays(MAX_DAYS_SINCE_LAST_CHECK), serialNumbers)) {
+ throw new CertPathValidatorException(
+ "Unable to verify the revocation status of one of the certificates "
+ + serialNumbers);
+ }
} catch (IOException ex2) {
throw new CertPathValidatorException(
"Unable to load stored revocation status", ex2);
}
- for (String serialNumber : serialNumbers) {
- if (!lastRevocationCheckData.containsKey(serialNumber)
- || lastRevocationCheckData
- .get(serialNumber)
- .isBefore(
- LocalDateTime.now().minusDays(MAX_DAYS_SINCE_LAST_CHECK))) {
- throw new CertPathValidatorException(
- "Unable to verify the revocation status of certificate "
- + serialNumber);
- }
+ }
+ }
+
+ private boolean isLastCheckedWithin(Duration lastCheckedWithin, List<String> serialNumbers)
+ throws IOException {
+ Map<String, LocalDateTime> lastRevocationCheckData = getLastRevocationCheckData();
+ for (String serialNumber : serialNumbers) {
+ if (!lastRevocationCheckData.containsKey(serialNumber)
+ || lastRevocationCheckData
+ .get(serialNumber)
+ .isBefore(LocalDateTime.now().minus(lastCheckedWithin))) {
+ return false;
}
}
+ return true;
}
private static boolean needToCheckRevocationStatus(
diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java
index bfd86d724583..9f9a9807d973 100644
--- a/services/core/java/com/android/server/security/FileIntegrityService.java
+++ b/services/core/java/com/android/server/security/FileIntegrityService.java
@@ -54,11 +54,6 @@ public class FileIntegrityService extends SystemService {
super(PermissionEnforcer.fromContext(context));
}
- @Override
- public boolean isApkVeritySupported() {
- return VerityUtils.isFsVeritySupported();
- }
-
private void checkCallerPackageName(String packageName) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
diff --git a/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java
index 687442b47fb3..cdeacaa2e43a 100644
--- a/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java
@@ -62,7 +62,7 @@ public class DataAggregator {
/** Initialize DataSources */
private void initialize() {
mDataSources.add(new SecurityLogSource(mContext, this));
- mDataSources.add(new NetworkLogSource(mContext, this));
+ mDataSources.add(new NetworkLogSource(this));
}
/**
diff --git a/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java
index f303a588d30c..fe0cf80a48f2 100644
--- a/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java
@@ -18,7 +18,6 @@ package com.android.server.security.intrusiondetection;
import android.app.admin.ConnectEvent;
import android.app.admin.DnsEvent;
-import android.content.Context;
import android.content.pm.PackageManagerInternal;
import android.net.IIpConnectivityMetrics;
import android.net.INetdEventCallback;
@@ -44,8 +43,7 @@ public class NetworkLogSource implements DataSource {
private IIpConnectivityMetrics mIpConnectivityMetrics;
private long mId;
- public NetworkLogSource(Context context, DataAggregator dataAggregator)
- throws SecurityException {
+ public NetworkLogSource(DataAggregator dataAggregator) throws SecurityException {
mDataAggregator = dataAggregator;
mPm = LocalServices.getService(PackageManagerInternal.class);
mId = 0;
diff --git a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java
index 142094c9d9f4..7501799198e8 100644
--- a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java
+++ b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java
@@ -19,14 +19,15 @@ package com.android.server.security.intrusiondetection;
import android.Manifest.permission;
import android.annotation.RequiresPermission;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.SecurityLog.SecurityEvent;
import android.content.Context;
import android.security.intrusiondetection.IntrusionDetectionEvent;
import android.util.Slog;
+import com.android.server.LocalServices;
+
import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -36,13 +37,13 @@ public class SecurityLogSource implements DataSource {
private SecurityEventCallback mEventCallback;
private DevicePolicyManager mDpm;
- private Executor mExecutor;
+ private DevicePolicyManagerInternal mDpmInternal;
private DataAggregator mDataAggregator;
public SecurityLogSource(Context context, DataAggregator dataAggregator) {
mDataAggregator = dataAggregator;
mDpm = context.getSystemService(DevicePolicyManager.class);
- mExecutor = Executors.newSingleThreadExecutor();
+ mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
mEventCallback = new SecurityEventCallback();
}
@@ -50,12 +51,13 @@ public class SecurityLogSource implements DataSource {
@RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
public void enable() {
enableAuditLog();
- mDpm.setAuditLogEventCallback(mExecutor, mEventCallback);
+ mDpmInternal.setInternalEventsCallback(mEventCallback);
}
@Override
@RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
public void disable() {
+ mDpmInternal.setInternalEventsCallback(null);
disableAuditLog();
}
@@ -82,10 +84,11 @@ public class SecurityLogSource implements DataSource {
@Override
public void accept(List<SecurityEvent> events) {
- if (events.size() == 0) {
+ if (events == null || events.size() == 0) {
Slog.w(TAG, "No events received; caller may not be authorized");
return;
}
+
List<IntrusionDetectionEvent> intrusionDetectionEvents =
events.stream()
.filter(event -> event != null)
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 7f2c68ff60b1..889b494ef538 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -3661,16 +3661,17 @@ public class StatsPullAtomService extends SystemService {
if (!packageNames.isEmpty()) {
for (String packageName : packageNames) {
- PackageInfo pkg;
+ int uid = INVALID_UID;
try {
- pkg = pm.getPackageInfoAsUser(packageName, 0, userId);
+ PackageInfo pkg = pm.getPackageInfoAsUser(packageName, 0, userId);
+ uid = pkg.applicationInfo.uid;
} catch (PackageManager.NameNotFoundException e) {
- Slog.w(TAG, "Role holder " + packageName + " not found");
- return StatsManager.PULL_SKIP;
+ Slog.w(TAG, "Role holder " + packageName + " not found for user "
+ + userId);
}
pulledData.add(FrameworkStatsLog.buildStatsEvent(
- atomTag, pkg.applicationInfo.uid, packageName, roleName));
+ atomTag, uid, packageName, roleName));
}
} else {
// Ensure that roles set to None are logged with an empty state.
@@ -3679,6 +3680,9 @@ public class StatsPullAtomService extends SystemService {
}
}
}
+ } catch (Throwable t) {
+ Log.e(TAG, "Could not read role holders", t);
+ return StatsManager.PULL_SKIP;
} finally {
Binder.restoreCallingIdentity(callingToken);
}
diff --git a/services/core/java/com/android/server/updates/CertPinInstallReceiver.java b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
index c03fbc3d0aed..250e99b47b1a 100644
--- a/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
@@ -16,9 +16,19 @@
package com.android.server.updates;
+import android.content.Context;
+import android.content.Intent;
+
public class CertPinInstallReceiver extends ConfigUpdateInstallReceiver {
public CertPinInstallReceiver() {
super("/data/misc/keychain/", "pins", "metadata/", "version");
}
+
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ if (!com.android.server.flags.Flags.certpininstallerRemoval()) {
+ super.onReceive(context, intent);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
index 395816902592..d06827ab0529 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
@@ -273,6 +273,9 @@ final class WearableSensingManagerPerUserService
@Override
public void onError() {
+ synchronized (mLock) {
+ ensureRemoteServiceInitiated();
+ }
synchronized (mSecureChannelLock) {
if (mSecureChannel != null
&& mSecureChannel
diff --git a/services/core/java/com/android/server/wearable/WearableSensingSecureChannel.java b/services/core/java/com/android/server/wearable/WearableSensingSecureChannel.java
index a16ff51e2d20..9f14ab7a70d3 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingSecureChannel.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingSecureChannel.java
@@ -156,6 +156,7 @@ final class WearableSensingSecureChannel {
new AssociationRequest.Builder()
.setDisplayName(CDM_ASSOCIATION_DISPLAY_NAME)
.setSelfManaged(true)
+ .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WEARABLE_SENSING)
.build(),
mLightWeightExecutor,
new CompanionDeviceManager.Callback() {
@@ -195,7 +196,8 @@ final class WearableSensingSecureChannel {
mCompanionDeviceManager.attachSystemDataTransport(
associationId,
new AutoCloseInputStream(mUnderlyingTransport),
- new AutoCloseOutputStream(mUnderlyingTransport));
+ new AutoCloseOutputStream(mUnderlyingTransport),
+ CompanionDeviceManager.TRANSPORT_FLAG_EXTEND_PATCH_DIFF);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index cf9c57aa634a..c37b5a055140 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -46,9 +46,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
-import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
-import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
-import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_HOME;
@@ -189,7 +186,6 @@ import static com.android.server.wm.ActivityRecordProto.STARTING_DISPLAYED;
import static com.android.server.wm.ActivityRecordProto.STARTING_MOVED;
import static com.android.server.wm.ActivityRecordProto.STARTING_WINDOW;
import static com.android.server.wm.ActivityRecordProto.STATE;
-import static com.android.server.wm.ActivityRecordProto.THUMBNAIL;
import static com.android.server.wm.ActivityRecordProto.TRANSLUCENT;
import static com.android.server.wm.ActivityRecordProto.VISIBLE;
import static com.android.server.wm.ActivityRecordProto.VISIBLE_REQUESTED;
@@ -265,7 +261,6 @@ import android.app.PictureInPictureParams;
import android.app.ResultInfo;
import android.app.WaitResult;
import android.app.WindowConfiguration;
-import android.app.admin.DevicePolicyManager;
import android.app.assist.ActivityId;
import android.app.compat.CompatChanges;
import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -300,7 +295,6 @@ import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.gui.DropInputMode;
import android.hardware.HardwareBuffer;
import android.net.Uri;
@@ -333,7 +327,6 @@ import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.InputApplicationHandle;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
-import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets;
@@ -341,7 +334,6 @@ import android.view.WindowInsets.Type;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.TransitionOldType;
-import android.view.animation.Animation;
import android.window.ActivityWindowInfo;
import android.window.ITaskFragmentOrganizer;
import android.window.RemoteTransition;
@@ -380,7 +372,6 @@ import com.android.server.uri.UriPermissionOwner;
import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.WindowManagerService.H;
-import com.android.server.wm.utils.InsetUtils;
import com.android.window.flags.Flags;
import dalvik.annotation.optimization.NeverCompile;
@@ -4701,8 +4692,6 @@ final class ActivityRecord extends WindowToken {
return true;
}
- // TODO: Transfer thumbnail
-
return false;
}
@@ -5707,7 +5696,21 @@ final class ActivityRecord extends WindowToken {
displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
mTransitionChangeFlags = 0;
- postApplyAnimation(visible, fromTransition);
+ // Set client visibility if:
+ // 1. The activity is becoming visible. This is usually no-op because assume that
+ // setVisibility(true) should have been called. Just in case if that was missed.
+ // 2. The activity is becoming invisible and not RESUMED state (it is usually PAUSED unless
+ // the activity is transient-hide). If the state is RESUMED, setVisibility(false) will be
+ // called until activityStopped. This is to avoid crashing apps that assume its view root
+ // won't be invisible before the activity is paused.
+ if (visible || mState != RESUMED) {
+ setClientVisible(visible);
+ }
+ // Notify the visibility change outside of transition in case onTransitionFinish is not
+ // called for updating snapshot states.
+ if (!fromTransition) {
+ mWmService.mSnapshotController.notifyAppVisibilityChanged(this, visible);
+ }
}
void commitVisibility(boolean visible, boolean performLayout) {
@@ -5726,75 +5729,6 @@ final class ActivityRecord extends WindowToken {
return mNeedsLetterboxedAnimation && isAnimating();
}
- /**
- * Post process after applying an app transition animation.
- *
- * <p class="note"><strong>Note: </strong> This function must be called after the animations
- * have been applied and {@link #commitVisibility}.</p>
- *
- * @param visible {@code true} if this {@link ActivityRecord} has become visible, otherwise
- * this has become invisible.
- * @param fromTransition {@code true} if this call is part of finishing a transition. This is
- * needed because the shell transition is no-longer active by the time
- * commitVisibility is called.
- */
- private void postApplyAnimation(boolean visible, boolean fromTransition) {
- final boolean usingShellTransitions = mTransitionController.isShellTransitionsEnabled();
- final boolean delayed = !usingShellTransitions && isAnimating(PARENTS | CHILDREN,
- ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION);
- if (!delayed && !usingShellTransitions) {
- // We aren't delayed anything, but exiting windows rely on the animation finished
- // callback being called in case the ActivityRecord was pretending to be delayed,
- // which we might have done because we were in closing/opening apps list.
- onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, null /* AnimationAdapter */);
- if (visible) {
- // The token was made immediately visible, there will be no entrance animation.
- // We need to inform the client the enter animation was finished.
- mEnteringAnimation = true;
- mWmService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(
- token);
- }
- }
-
- // If we're becoming visible, immediately change client visibility as well. there seem
- // to be some edge cases where we change our visibility but client visibility never gets
- // updated.
- // If we're becoming invisible, update the client visibility if we are not running an
- // animation and aren't in RESUMED state. Otherwise, we'll update client visibility in
- // onAnimationFinished or activityStopped.
- if (visible || (mState != RESUMED && (usingShellTransitions || !isAnimating(
- PARENTS, ANIMATION_TYPE_APP_TRANSITION)))) {
- setClientVisible(visible);
- }
-
- final DisplayContent displayContent = getDisplayContent();
- if (!displayContent.mClosingApps.contains(this)
- && !displayContent.mOpeningApps.contains(this)
- && !fromTransition) {
- // Take the screenshot before possibly hiding the WSA, otherwise the screenshot
- // will not be taken.
- mWmService.mSnapshotController.notifyAppVisibilityChanged(this, visible);
- }
-
- // If we are hidden but there is no delay needed we immediately
- // apply the Surface transaction so that the ActivityManager
- // can have some guarantee on the Surface state following
- // setting the visibility. This captures cases like dismissing
- // the docked or root pinned task where there is no app transition.
- //
- // In the case of a "Null" animation, there will be
- // no animation but there will still be a transition set.
- // We still need to delay hiding the surface such that it
- // can be synchronized with showing the next surface in the transition.
- if (!usingShellTransitions && !isVisible() && !delayed
- && !displayContent.mAppTransition.isTransitionSet()) {
- forAllWindows(win -> {
- win.mWinAnimator.hide(getPendingTransaction(), "immediately hidden");
- }, true);
- scheduleAnimation();
- }
- }
-
/** Updates draw state and shows drawn windows. */
void commitFinishDrawing(SurfaceControl.Transaction t) {
boolean committed = false;
@@ -7597,9 +7531,6 @@ final class ActivityRecord extends WindowToken {
mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getPendingTransaction());
}
}
- if (mThumbnail != null) {
- mThumbnail.setShowing(getPendingTransaction(), show);
- }
mLastSurfaceShowing = show;
super.prepareSurfaces();
}
@@ -7611,84 +7542,6 @@ final class ActivityRecord extends WindowToken {
return mLastSurfaceShowing;
}
- void attachThumbnailAnimation() {
- if (!isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
- return;
- }
- final HardwareBuffer thumbnailHeader =
- getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(task);
- if (thumbnailHeader == null) {
- ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", task);
- return;
- }
- clearThumbnail();
- final Transaction transaction = getAnimatingContainer().getPendingTransaction();
- mThumbnail = new WindowContainerThumbnail(transaction, getAnimatingContainer(),
- thumbnailHeader);
- mThumbnail.startAnimation(transaction, loadThumbnailAnimation(thumbnailHeader));
- }
-
- /**
- * Attaches a surface with a thumbnail for the
- * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation.
- */
- void attachCrossProfileAppsThumbnailAnimation() {
- if (!isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
- return;
- }
- clearThumbnail();
-
- final WindowState win = findMainWindow();
- if (win == null) {
- return;
- }
- final Rect frame = win.getRelativeFrame();
- final Context context = mAtmService.getUiContext();
- final Drawable thumbnailDrawable;
- if (task.mUserId == mWmService.mCurrentUserId) {
- thumbnailDrawable = context.getDrawable(R.drawable.ic_account_circle);
- } else {
- final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
- thumbnailDrawable = dpm.getResources().getDrawable(
- WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
- () -> context.getDrawable(R.drawable.ic_corp_badge));
- }
- final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
- .createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
- if (thumbnail == null) {
- return;
- }
- final Transaction transaction = getPendingTransaction();
- mThumbnail = new WindowContainerThumbnail(transaction, getTask(), thumbnail);
- final Animation animation =
- getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(
- frame);
- mThumbnail.startAnimation(transaction, animation, new Point(frame.left, frame.top));
- }
-
- private Animation loadThumbnailAnimation(HardwareBuffer thumbnailHeader) {
- final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
-
- // If this is a multi-window scenario, we use the windows frame as
- // destination of the thumbnail header animation. If this is a full screen
- // window scenario, we use the whole display as the target.
- WindowState win = findMainWindow();
- Rect insets;
- Rect appRect;
- if (win != null) {
- insets = win.getInsetsStateWithVisibilityOverride().calculateInsets(
- win.getFrame(), Type.systemBars(), false /* ignoreVisibility */).toRect();
- appRect = new Rect(win.getFrame());
- appRect.inset(insets);
- } else {
- insets = null;
- appRect = new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
- }
- final Configuration displayConfig = mDisplayContent.getConfiguration();
- return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
- appRect, insets, thumbnailHeader, task, displayConfig.orientation);
- }
-
@Override
public void onAnimationLeashLost(Transaction t) {
super.onAnimationLeashLost(t);
@@ -7715,7 +7568,6 @@ final class ActivityRecord extends WindowToken {
setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
"ActivityRecord");
- clearThumbnail();
setClientVisible(isVisible() || mVisibleRequested);
getDisplayContent().computeImeTargetIfNeeded(this);
@@ -7725,12 +7577,6 @@ final class ActivityRecord extends WindowToken {
this, reportedVisible, okToDisplay(), okToAnimate(),
isStartingWindowDisplayed());
- // clean up thumbnail window
- if (mThumbnail != null) {
- mThumbnail.destroy();
- mThumbnail = null;
- }
-
// WindowState.onExitAnimationDone might modify the children list, so make a copy and then
// traverse the copy.
final ArrayList<WindowState> children = new ArrayList<>(mChildren);
@@ -7769,20 +7615,6 @@ final class ActivityRecord extends WindowToken {
}
}
- @Override
- void cancelAnimation() {
- super.cancelAnimation();
- clearThumbnail();
- }
-
- private void clearThumbnail() {
- if (mThumbnail == null) {
- return;
- }
- mThumbnail.destroy();
- mThumbnail = null;
- }
-
public @TransitionOldType int getTransit() {
return mTransit;
}
@@ -8219,6 +8051,7 @@ final class ActivityRecord extends WindowToken {
mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
getResolvedOverrideConfiguration().seq = mConfigurationSeq;
+ // TODO(b/392069771): Move to AppCompatSandboxingPolicy.
// Sandbox max bounds by setting it to the activity bounds, if activity is letterboxed, or
// has or will have mAppCompatDisplayInsets for size compat. Also forces an activity to be
// sandboxed or not depending upon the configuration settings.
@@ -8247,6 +8080,9 @@ final class ActivityRecord extends WindowToken {
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
}
+ mAppCompatController.getSandboxingPolicy().sandboxBoundsIfNeeded(resolvedConfig,
+ parentWindowingMode);
+
applySizeOverrideIfNeeded(
mDisplayContent,
info.applicationInfo,
@@ -9728,9 +9564,6 @@ final class ActivityRecord extends WindowToken {
proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
proto.write(IS_ANIMATING, isAnimating(TRANSITION | PARENTS | CHILDREN,
ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION));
- if (mThumbnail != null){
- mThumbnail.dumpDebug(proto, THUMBNAIL);
- }
proto.write(FILLS_PARENT, fillsParent());
proto.write(APP_STOPPED, mAppStopped);
proto.write(TRANSLUCENT, !occludesParent());
@@ -9834,31 +9667,6 @@ final class ActivityRecord extends WindowToken {
}
@Override
- RemoteAnimationTarget createRemoteAnimationTarget(
- RemoteAnimationController.RemoteAnimationRecord record) {
- final WindowState mainWindow = findMainWindow();
- if (task == null || mainWindow == null) {
- return null;
- }
- final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
- task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect();
- InsetUtils.addInsets(insets, getLetterboxInsets());
-
- final RemoteAnimationTarget target = new RemoteAnimationTarget(task.mTaskId,
- record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(),
- new Rect(), insets,
- getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
- record.mAdapter.mEndBounds, task.getWindowConfiguration(),
- false /*isNotInRecents*/,
- record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
- record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
- target.setShowBackdrop(record.mShowBackdrop);
- target.setWillShowImeOnTarget(mStartingData != null && mStartingData.hasImeSurface());
- target.hasAnimatingParent = record.hasAnimatingParent();
- return target;
- }
-
- @Override
boolean canCreateRemoteAnimationTarget() {
return true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 6a5adca91e39..b607b0fce9ab 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -145,6 +145,7 @@ import android.util.SparseIntArray;
import android.view.Display;
import android.webkit.URLUtil;
import android.window.ActivityWindowInfo;
+import android.window.DesktopExperienceFlags;
import android.window.DesktopModeFlags;
import com.android.internal.R;
@@ -2916,6 +2917,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
/** The helper to calculate whether a container is opaque. */
static class OpaqueContainerHelper implements Predicate<ActivityRecord> {
+ private final boolean mEnableMultipleDesktopsBackend =
+ DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue();
private ActivityRecord mStarting;
private boolean mIgnoringInvisibleActivity;
private boolean mIgnoringKeyguard;
@@ -2938,7 +2941,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
mIgnoringKeyguard = ignoringKeyguard;
final boolean isOpaque;
- if (!Flags.enableMultipleDesktopsBackend()) {
+ if (!mEnableMultipleDesktopsBackend) {
isOpaque = container.getActivity(this,
true /* traverseTopToBottom */, null /* boundary */) != null;
} else {
@@ -2949,13 +2952,16 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
private boolean isOpaqueInner(@NonNull WindowContainer<?> container) {
- // If it's a leaf task fragment, then opacity is calculated based on its activities.
- if (container.asTaskFragment() != null
- && ((TaskFragment) container).isLeafTaskFragment()) {
+ final boolean isActivity = container.asActivityRecord() != null;
+ final boolean isLeafTaskFragment = container.asTaskFragment() != null
+ && ((TaskFragment) container).isLeafTaskFragment();
+ if (isActivity || isLeafTaskFragment) {
+ // When it is an activity or leaf task fragment, then opacity is calculated based
+ // on itself or its activities.
return container.getActivity(this,
true /* traverseTopToBottom */, null /* boundary */) != null;
}
- // When not a leaf, it's considered opaque if any of its opaque children fill this
+ // Otherwise, it's considered opaque if any of its opaque children fill this
// container, unless the children are adjacent fragments, in which case as long as they
// are all opaque then |container| is also considered opaque, even if the adjacent
// task fragment aren't filling.
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
index bed95face1c9..fc504796b0ac 100644
--- a/services/core/java/com/android/server/wm/AppCompatController.java
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -44,6 +44,8 @@ class AppCompatController {
private final AppCompatLetterboxPolicy mLetterboxPolicy;
@NonNull
private final AppCompatSizeCompatModePolicy mSizeCompatModePolicy;
+ @NonNull
+ private final AppCompatSandboxingPolicy mSandboxingPolicy;
AppCompatController(@NonNull WindowManagerService wmService,
@NonNull ActivityRecord activityRecord) {
@@ -66,6 +68,7 @@ class AppCompatController {
mAppCompatOverrides, mTransparentPolicy, wmService.mAppCompatConfiguration);
mSizeCompatModePolicy = new AppCompatSizeCompatModePolicy(activityRecord,
mAppCompatOverrides);
+ mSandboxingPolicy = new AppCompatSandboxingPolicy(activityRecord);
}
@NonNull
@@ -143,6 +146,11 @@ class AppCompatController {
return mSizeCompatModePolicy;
}
+ @NonNull
+ AppCompatSandboxingPolicy getSandboxingPolicy() {
+ return mSandboxingPolicy;
+ }
+
void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
getTransparentPolicy().dump(pw, prefix);
getLetterboxPolicy().dump(pw, prefix);
diff --git a/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java b/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java
new file mode 100644
index 000000000000..26cf32b12d4f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2025 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.wm;
+
+import static com.android.server.wm.AppCompatUtils.isInDesktopMode;
+
+import android.annotation.NonNull;
+import android.app.WindowConfiguration.WindowingMode;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+
+import com.android.window.flags.Flags;
+
+/**
+ * Encapsulate logic related to sandboxing for app compatibility.
+ */
+class AppCompatSandboxingPolicy {
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+
+ AppCompatSandboxingPolicy(@NonNull ActivityRecord activityRecord) {
+ mActivityRecord = activityRecord;
+ }
+
+ /**
+ * In freeform, the container bounds are scaled with app bounds. Activity bounds can be
+ * outside of its container bounds if insets are coupled with configuration outside of
+ * freeform and maintained in freeform for size compat mode.
+ *
+ * <p>Sandbox activity bounds in freeform to app bounds to force app to display within the
+ * container. This prevents UI cropping when activities can draw below insets which are
+ * normally excluded from appBounds before targetSDK < 35
+ * (see ConfigurationContainer#applySizeOverrideIfNeeded).
+ */
+ void sandboxBoundsIfNeeded(@NonNull Configuration resolvedConfig,
+ @WindowingMode int windowingMode) {
+ if (!Flags.excludeCaptionFromAppBounds()) {
+ return;
+ }
+
+ if (isInDesktopMode(mActivityRecord.mAtmService.mContext, windowingMode)) {
+ Rect appBounds = resolvedConfig.windowConfiguration.getAppBounds();
+ if (appBounds == null || appBounds.isEmpty()) {
+ // When there is no override bounds, the activity will inherit the bounds from
+ // parent.
+ appBounds = mActivityRecord.mResolveConfigHint.mParentAppBoundsOverride;
+ }
+ resolvedConfig.windowConfiguration.setBounds(appBounds);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
index bbc33004ee54..2cfa242bc5fe 100644
--- a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
@@ -17,14 +17,13 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_METADATA;
import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_OVERRIDE;
import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_METADATA;
import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
-import static com.android.server.wm.DesktopModeHelper.canEnterDesktopMode;
+import static com.android.server.wm.AppCompatUtils.isInDesktopMode;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -545,9 +544,8 @@ class AppCompatSizeCompatModePolicy {
// Allow an application to be up-scaled if its window is smaller than its
// original container or if it's a freeform window in desktop mode.
boolean shouldAllowUpscaling = !(contentW <= viewportW && contentH <= viewportH)
- || (canEnterDesktopMode(mActivityRecord.mAtmService.mContext)
- && newParentConfig.windowConfiguration.getWindowingMode()
- == WINDOWING_MODE_FREEFORM);
+ || isInDesktopMode(mActivityRecord.mAtmService.mContext,
+ newParentConfig.windowConfiguration.getWindowingMode());
return shouldAllowUpscaling ? Math.min(
(float) viewportW / contentW, (float) viewportH / contentH) : 1f;
}
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
index 3e054fc40540..146044008b3f 100644
--- a/services/core/java/com/android/server/wm/AppCompatUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -16,16 +16,20 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.DesktopModeHelper.canEnterDesktopMode;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppCompatTaskInfo;
import android.app.CameraCompatTaskInfo;
import android.app.TaskInfo;
+import android.app.WindowConfiguration.WindowingMode;
+import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.view.InsetsSource;
@@ -276,6 +280,14 @@ final class AppCompatUtils {
inOutConfig.windowConfiguration.getAppBounds().offset(offsetX, offsetY);
}
+ /**
+ * Return {@code true} if window is currently in desktop mode.
+ */
+ static boolean isInDesktopMode(@NonNull Context context,
+ @WindowingMode int parentWindowingMode) {
+ return parentWindowingMode == WINDOWING_MODE_FREEFORM && canEnterDesktopMode(context);
+ }
+
private static void clearAppCompatTaskInfo(@NonNull AppCompatTaskInfo info) {
info.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 9c4b722feb47..d98ad8bb9e05 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -231,8 +231,6 @@ public class AppTransition implements Dump {
private final int mDefaultWindowAnimationStyleResId;
private boolean mOverrideTaskTransition;
- private RemoteAnimationController mRemoteAnimationController;
-
final Handler mHandler;
final Runnable mHandleAppTransitionTimeoutRunnable = () -> handleAppTransitionTimeout();
@@ -398,9 +396,7 @@ public class AppTransition implements Dump {
: SystemClock.uptimeMillis(),
AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
- if (mRemoteAnimationController != null) {
- mRemoteAnimationController.goodToGo(transit);
- } else if ((isTaskOpenTransitOld(transit) || transit == TRANSIT_OLD_WALLPAPER_CLOSE)
+ if ((isTaskOpenTransitOld(transit) || transit == TRANSIT_OLD_WALLPAPER_CLOSE)
&& topOpeningAnim != null) {
if (mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()) {
final NavBarFadeAnimationController controller =
@@ -424,7 +420,6 @@ public class AppTransition implements Dump {
mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
mNextAppTransitionOverrideRequested = false;
mNextAppTransitionAnimationsSpecs.clear();
- mRemoteAnimationController = null;
mNextAppTransitionAnimationsSpecsFuture = null;
mDefaultNextAppTransitionAnimationSpec = null;
mAnimationFinishedCallback = null;
@@ -442,13 +437,6 @@ public class AppTransition implements Dump {
final boolean keyguardGoingAwayCancelled = mNextAppTransitionRequests.contains(
TRANSIT_KEYGUARD_GOING_AWAY);
- // The RemoteAnimationControl didn't register AppTransitionListener and
- // only initialized the finish and timeout callback when goodToGo().
- // So cancel the remote animation here to prevent the animation can't do
- // finish after transition state cleared.
- if (mRemoteAnimationController != null) {
- mRemoteAnimationController.cancelAnimation("freeze");
- }
mNextAppTransitionRequests.clear();
clear();
setReady();
@@ -719,10 +707,6 @@ public class AppTransition implements Dump {
&& !mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_GOING_AWAY);
}
- RemoteAnimationController getRemoteAnimationController() {
- return mRemoteAnimationController;
- }
-
/**
*
* @param frame These are the bounds of the window when it finishes the animation. This is where
@@ -1082,17 +1066,6 @@ public class AppTransition implements Dump {
void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter,
boolean sync, boolean isActivityEmbedding) {
- ProtoLog.i(WM_DEBUG_APP_TRANSITIONS, "Override pending remote transitionSet=%b adapter=%s",
- isTransitionSet(), remoteAnimationAdapter);
- if (isTransitionSet() && !mNextAppTransitionIsSync) {
- // ActivityEmbedding animation will run by the app process for which we want to respect
- // the app override for whether or not to show background color.
- clear(!isActivityEmbedding /* clearAppOverride */);
- mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE;
- mRemoteAnimationController = new RemoteAnimationController(mService, mDisplayContent,
- remoteAnimationAdapter, mHandler, isActivityEmbedding);
- mNextAppTransitionIsSync = sync;
- }
}
void overrideInPlaceAppTransition(String packageName, int anim) {
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index e76a83453a9d..094ad187686c 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -190,7 +190,9 @@ class BackNavigationController {
currentActivity = window.mActivityRecord;
currentTask = window.getTask();
if ((currentTask != null && !currentTask.isVisibleRequested())
- || (currentActivity != null && !currentActivity.isVisibleRequested())) {
+ || (currentActivity != null && !currentActivity.isVisibleRequested())
+ || (currentActivity != null && currentTask != null
+ && currentTask.getTopNonFinishingActivity() != currentActivity)) {
// Closing transition is happening on focus window and should be update soon,
// don't drive back navigation with it.
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Focus window is closing.");
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index 4eaa11bac016..f473b7b7e4fb 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -60,10 +60,11 @@ class DeferredDisplayUpdater {
*/
@VisibleForTesting
static final DisplayInfoFieldsUpdater DEFERRABLE_FIELDS = (out, override) -> {
- // Treat unique id and address change as WM-specific display change as we re-query display
- // settings and parameters based on it which could cause window changes
+ // Treat unique id, address, and canHostTasks change as WM-specific display change as we
+ // re-query display settings and parameters based on it which could cause window changes.
out.uniqueId = override.uniqueId;
out.address = override.address;
+ out.canHostTasks = override.canHostTasks;
// Also apply WM-override fields, since they might produce differences in window hierarchy
WM_OVERRIDE_FIELDS.setFields(out, override);
@@ -433,7 +434,7 @@ class DeferredDisplayUpdater {
second.thermalRefreshRateThrottling)
|| !Objects.equals(first.thermalBrightnessThrottlingDataId,
second.thermalBrightnessThrottlingDataId)
- || first.canHostTasks != second.canHostTasks) {
+ ) {
diff |= DIFF_NOT_WM_DEFERRABLE;
}
@@ -454,6 +455,7 @@ class DeferredDisplayUpdater {
|| !Objects.equals(first.displayShape, second.displayShape)
|| !Objects.equals(first.uniqueId, second.uniqueId)
|| !Objects.equals(first.address, second.address)
+ || first.canHostTasks != second.canHostTasks
) {
diff |= DIFF_WM_DEFERRABLE;
}
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index f35930700653..c2255d8d011a 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -51,13 +51,8 @@ public final class DesktopModeHelper {
}
/**
- * Return {@code true} if the current device can hosts desktop sessions on its internal display.
+ * Return {@code true} if the current device supports desktop mode.
*/
- @VisibleForTesting
- static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
- return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops);
- }
-
// TODO(b/337819319): use a companion object instead.
private static boolean isDesktopModeSupported(@NonNull Context context) {
return context.getResources().getBoolean(R.bool.config_isDesktopModeSupported);
@@ -68,32 +63,45 @@ public final class DesktopModeHelper {
}
/**
+ * Return {@code true} if the current device can hosts desktop sessions on its internal display.
+ */
+ @VisibleForTesting
+ static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
+ return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops);
+ }
+
+ /**
* Check if Desktop mode should be enabled because the dev option is shown and enabled.
*/
private static boolean isDesktopModeEnabledByDevOption(@NonNull Context context) {
return DesktopModeFlags.isDesktopModeForcedEnabled() && (isDesktopModeDevOptionsSupported(
- context) || isInternalDisplayEligibleToHostDesktops(context));
+ context) || isDeviceEligibleForDesktopMode(context));
}
@VisibleForTesting
- static boolean isInternalDisplayEligibleToHostDesktops(@NonNull Context context) {
- return !shouldEnforceDeviceRestrictions() || canInternalDisplayHostDesktops(context) || (
- Flags.enableDesktopModeThroughDevOption() && isDesktopModeDevOptionsSupported(
- context));
+ static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) {
+ if (!shouldEnforceDeviceRestrictions()) {
+ return true;
+ }
+ final boolean desktopModeSupported = isDesktopModeSupported(context)
+ && canInternalDisplayHostDesktops(context);
+ final boolean desktopModeSupportedByDevOptions =
+ Flags.enableDesktopModeThroughDevOption()
+ && isDesktopModeDevOptionsSupported(context);
+ return desktopModeSupported || desktopModeSupportedByDevOptions;
}
/**
* Return {@code true} if desktop mode can be entered on the current device.
*/
static boolean canEnterDesktopMode(@NonNull Context context) {
- return (isInternalDisplayEligibleToHostDesktops(context)
- && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue()
- && (isDesktopModeSupported(context) || !shouldEnforceDeviceRestrictions()))
+ return (isDeviceEligibleForDesktopMode(context)
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue())
|| isDesktopModeEnabledByDevOption(context);
}
/** Returns {@code true} if desktop experience wallpaper is supported on this device. */
public static boolean isDeviceEligibleForDesktopExperienceWallpaper(@NonNull Context context) {
- return enableConnectedDisplaysWallpaper() && canEnterDesktopMode(context);
+ return enableConnectedDisplaysWallpaper() && isDeviceEligibleForDesktopMode(context);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 682f3d8cf1e5..703ce7d24468 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3239,25 +3239,43 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
Slog.e(TAG, "ShouldShowSystemDecors shouldn't be updated when the flag is off.");
}
- final boolean shouldShow;
- if (isDefaultDisplay) {
- shouldShow = true;
- } else if (isPrivate()) {
- shouldShow = false;
- } else {
- shouldShow = mDisplay.canHostTasks();
+ final boolean shouldShowContent;
+ if (!allowContentModeSwitch()) {
+ return;
}
+ shouldShowContent = mDisplay.canHostTasks();
- if (shouldShow == mWmService.mDisplayWindowSettings.shouldShowSystemDecorsLocked(this)) {
+ if (shouldShowContent == mWmService.mDisplayWindowSettings
+ .shouldShowSystemDecorsLocked(this)) {
return;
}
- mWmService.mDisplayWindowSettings.setShouldShowSystemDecorsLocked(this, shouldShow);
+ mWmService.mDisplayWindowSettings.setShouldShowSystemDecorsLocked(this, shouldShowContent);
- if (!shouldShow) {
+ if (!shouldShowContent) {
clearAllTasksOnDisplay(null /* clearTasksCallback */, false /* isRemovingDisplay */);
}
}
+ private boolean allowContentModeSwitch() {
+ // The default display should always show system decorations.
+ if (isDefaultDisplay) {
+ return false;
+ }
+
+ // Private display should never show system decorations.
+ if (isPrivate()) {
+ return false;
+ }
+
+ // TODO(b/391965805): Remove this after introducing FLAG_ALLOW_SYSTEM_DECORATIONS_CHANGE.
+ // Virtual displays cannot add or remove system decorations during their lifecycle.
+ if (mDisplay.getType() == Display.TYPE_VIRTUAL) {
+ return false;
+ }
+
+ return true;
+ }
+
DisplayCutout loadDisplayCutout(int displayWidth, int displayHeight) {
if (mDisplayPolicy == null || mInitialDisplayCutout == null) {
return null;
@@ -6578,22 +6596,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
.getKeyguardController().isKeyguardLocked(mDisplayId);
}
- boolean isKeyguardLockedOrAodShowing() {
- return isKeyguardLocked() || isAodShowing();
- }
-
- /**
- * @return whether aod is showing for this display
- */
- boolean isAodShowing() {
- final boolean isAodShowing = mRootWindowContainer.mTaskSupervisor
- .getKeyguardController().isAodShowing(mDisplayId);
- if (mDisplayId == DEFAULT_DISPLAY && isAodShowing) {
- return !isKeyguardGoingAway();
- }
- return isAodShowing;
- }
-
/**
* @return whether keyguard is going away on this display
*/
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 69f32cb7b8ea..84281b8fbecf 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -122,7 +122,7 @@ class DragState {
float mThumbOffsetX, mThumbOffsetY;
InputInterceptor mInputInterceptor;
ArrayList<WindowState> mNotifiedWindows;
- boolean mDragInProgress;
+ private boolean mDragInProgress;
// Set to non -1 value if a valid app requests DRAG_FLAG_HIDE_CALLING_TASK_ON_DRAG_START
int mCallingTaskIdToHide;
/**
@@ -161,7 +161,7 @@ class DragState {
private boolean mIsClosing;
// Stores the last drop event which was reported to a valid drop target window, or null
- // otherwise. This drop event will contain private info and should only be consumed by the
+ // otherwise. This drop event will contain private info and should only be consumed by the
// unhandled drag listener.
DragEvent mUnhandledDropEvent;
@@ -243,7 +243,7 @@ class DragState {
for (WindowState ws : mNotifiedWindows) {
float inWindowX = 0;
float inWindowY = 0;
- SurfaceControl dragSurface = null;
+ boolean includeDragSurface = false;
if (!mDragResult && (ws.mSession.mPid == mPid)) {
// Report unconsumed drop location back to the app that started the drag.
inWindowX = ws.translateToWindowX(mCurrentDisplayX);
@@ -251,13 +251,10 @@ class DragState {
if (relinquishDragSurfaceToDragSource()) {
// If requested (and allowed), report the drag surface back to the app
// starting the drag to handle the return animation
- dragSurface = mSurfaceControl;
+ includeDragSurface = true;
}
}
- DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED, inWindowX,
- inWindowY, mThumbOffsetX, mThumbOffsetY,
- mCurrentDisplayContent.getDisplayId(), mFlags, null, null, null,
- dragSurface, null, mDragResult);
+ DragEvent event = obtainDragEndedEvent(inWindowX, inWindowY, includeDragSurface);
try {
if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DRAG_ENDED to " + ws);
ws.mClient.dispatchDragEvent(event);
@@ -310,10 +307,10 @@ class DragState {
/**
* Creates the drop event for dispatching to the unhandled drag.
- * TODO(b/384841906): Update `inWindowX` and `inWindowY` to be display-coordinate.
*/
- private DragEvent createUnhandledDropEvent(float inWindowX, float inWindowY) {
- return obtainDragEvent(DragEvent.ACTION_DROP, inWindowX, inWindowY, mDataDescription, mData,
+ private DragEvent createUnhandledDropEvent(float inDisplayX, float inDisplayY) {
+ return obtainDragEvent(DragEvent.ACTION_DROP, inDisplayX, inDisplayY, mDataDescription,
+ mData,
/* includeDragSurface= */ true,
/* includeDragFlags= */ true, null /* dragAndDropPermissions */);
}
@@ -370,11 +367,8 @@ class DragState {
}
final WindowState touchedWin = mService.mInputToWindowMap.get(token);
- // TODO(b/384841906): The x, y here when sent to a window and unhandled, will still be
- // relative to the window it was originally sent to. Need to update this to actually be
- // display-coordinate.
- final DragEvent unhandledDropEvent = createUnhandledDropEvent(inWindowX, inWindowY);
if (!isWindowNotified(touchedWin)) {
+ final DragEvent unhandledDropEvent = createUnhandledDropEvent(inWindowX, inWindowY);
// Delegate to the unhandled drag listener as a first pass
if (mDragDropController.notifyUnhandledDrop(unhandledDropEvent, "unhandled-drop")) {
// The unhandled drag listener will call back to notify whether it has consumed
@@ -392,6 +386,8 @@ class DragState {
}
if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DROP to " + touchedWin);
+ final DragEvent unhandledDropEvent = createUnhandledDropEvent(
+ touchedWin.getBounds().left + inWindowX, touchedWin.getBounds().top + inWindowY);
final IBinder clientToken = touchedWin.mClient.asBinder();
final DragEvent event = createDropEvent(inWindowX, inWindowY, touchedWin);
@@ -776,28 +772,37 @@ class DragState {
displayId, (int) (displayX - mThumbOffsetX), (int) (displayY - mThumbOffsetY));
}
- /**
- * Returns true if it has sent DRAG_STARTED broadcast out but has not been sent DRAG_END
- * broadcast.
- */
- boolean isInProgress() {
- return mDragInProgress;
+ private DragEvent obtainDragEndedEvent(float x, float y, boolean includeDragSurface) {
+ return obtainDragEvent(DragEvent.ACTION_DRAG_ENDED, x, y, /* description= */
+ null, /* data= */ null, includeDragSurface, /* includeDragFlags= */
+ true, /* dragAndDropPermissions= */ null, mDragResult);
+ }
+
+ private DragEvent obtainDragEvent(int action, float x, float y, ClipDescription description,
+ ClipData data, boolean includeDragSurface, boolean includeDragFlags,
+ IDragAndDropPermissions dragAndDropPermissions) {
+ return obtainDragEvent(action, x, y, description, data, includeDragSurface,
+ includeDragFlags, dragAndDropPermissions, /* dragResult= */ false);
}
/**
* `x` and `y` here varies between local window coordinate, relative coordinate to another
* window and local display coordinate, all depending on the `action`. Please take a look
* at the callers to determine the type.
- * TODO(b/384845022): Properly document the events sent based on the event type.
+ * - ACTION_DRAG_STARTED: (x, y) is relative coordinate to the target window's origin
+ * (possible to have negative values).
+ * - ACTION_DROP:
+ * --- UnhandledDropEvent: (x, y) is in display space coordinate.
+ * --- DropEvent: (x, y) is in local window coordinate where event is targeted to.
+ * - ACTION_DRAG_ENDED: (x, y) is in local window coordinate where event is targeted to.
*/
private DragEvent obtainDragEvent(int action, float x, float y, ClipDescription description,
ClipData data, boolean includeDragSurface, boolean includeDragFlags,
- IDragAndDropPermissions dragAndDropPermissions) {
+ IDragAndDropPermissions dragAndDropPermissions, boolean dragResult) {
return DragEvent.obtain(action, x, y, mThumbOffsetX, mThumbOffsetY,
mCurrentDisplayContent.getDisplayId(), includeDragFlags ? mFlags : 0,
null /* localState */, description, data,
- includeDragSurface ? mSurfaceControl : null, dragAndDropPermissions,
- false /* result */);
+ includeDragSurface ? mSurfaceControl : null, dragAndDropPermissions, dragResult);
}
private ValueAnimator createReturnAnimationLocked() {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index dd2f49e171a8..6091b8334438 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -18,7 +18,6 @@ package com.android.server.wm;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
@@ -217,9 +216,6 @@ class KeyguardController {
} else if (keyguardShowing && !state.mKeyguardShowing) {
transition.addFlag(TRANSIT_FLAG_KEYGUARD_APPEARING);
}
- if (mWindowManager.mFlags.mAodTransition && aodShowing && !state.mAodShowing) {
- transition.addFlag(TRANSIT_FLAG_AOD_APPEARING);
- }
}
}
// Update the task snapshot if the screen will not be turned off. To make sure that the
@@ -242,27 +238,19 @@ class KeyguardController {
state.mAodShowing = aodShowing;
state.writeEventLog("setKeyguardShown");
- if (keyguardChanged || aodChanged) {
- if (keyguardChanged) {
- // Irrelevant to AOD.
- state.mKeyguardGoingAway = false;
- if (keyguardShowing) {
- state.mDismissalRequested = false;
- }
+ if (keyguardChanged) {
+ // Irrelevant to AOD.
+ state.mKeyguardGoingAway = false;
+ if (keyguardShowing) {
+ state.mDismissalRequested = false;
}
if (goingAwayRemoved
- || (keyguardShowing && !Display.isOffState(dc.getDisplayInfo().state))
- || (mWindowManager.mFlags.mAodTransition && aodShowing)) {
+ || (keyguardShowing && !Display.isOffState(dc.getDisplayInfo().state))) {
// Keyguard decided to show or stopped going away. Send a transition to animate back
// to the locked state before holding the sleep token again
if (!ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
dc.requestTransitionAndLegacyPrepare(
TRANSIT_TO_FRONT, TRANSIT_FLAG_KEYGUARD_APPEARING);
- if (mWindowManager.mFlags.mAodTransition && aodShowing
- && dc.mTransitionController.isCollecting()) {
- dc.mTransitionController.getCollectingTransition().addFlag(
- TRANSIT_FLAG_AOD_APPEARING);
- }
}
dc.mWallpaperController.adjustWallpaperWindows();
dc.executeAppTransition();
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
deleted file mode 100644
index 91598c5cc27a..000000000000
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ /dev/null
@@ -1,227 +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.server.wm;
-
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
-import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE;
-
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_REMOTE_ANIMATIONS;
-import static com.android.server.wm.AnimationAdapterProto.REMOTE;
-import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
-
-import android.annotation.NonNull;
-import android.graphics.Rect;
-import android.os.SystemClock;
-import android.util.proto.ProtoOutputStream;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.WindowManager;
-
-import com.android.internal.protolog.ProtoLog;
-import com.android.server.policy.WindowManagerPolicy;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-class NonAppWindowAnimationAdapter implements AnimationAdapter {
-
- private final WindowContainer mWindowContainer;
- private RemoteAnimationTarget mTarget;
- private SurfaceControl mCapturedLeash;
- private SurfaceAnimator.OnAnimationFinishedCallback mCapturedLeashFinishCallback;
- private @SurfaceAnimator.AnimationType int mLastAnimationType;
-
- private long mDurationHint;
- private long mStatusBarTransitionDelay;
-
- @Override
- public boolean getShowWallpaper() {
- return false;
- }
-
- NonAppWindowAnimationAdapter(WindowContainer w, long durationHint,
- long statusBarTransitionDelay) {
- mWindowContainer = w;
- mDurationHint = durationHint;
- mStatusBarTransitionDelay = statusBarTransitionDelay;
- }
-
- static RemoteAnimationTarget[] startNonAppWindowAnimations(WindowManagerService service,
- DisplayContent displayContent, @WindowManager.TransitionOldType int transit,
- long durationHint, long statusBarTransitionDelay,
- ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
- final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
- if (shouldStartNonAppWindowAnimationsForKeyguardExit(transit)) {
- startNonAppWindowAnimationsForKeyguardExit(
- service, durationHint, statusBarTransitionDelay, targets, adaptersOut);
- } else if (shouldAttachNavBarToApp(service, displayContent, transit)) {
- startNavigationBarWindowAnimation(
- displayContent, durationHint, statusBarTransitionDelay, targets,
- adaptersOut);
- }
- return targets.toArray(new RemoteAnimationTarget[targets.size()]);
- }
-
- static boolean shouldStartNonAppWindowAnimationsForKeyguardExit(
- @WindowManager.TransitionOldType int transit) {
- return transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
- || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
- }
-
- static boolean shouldAttachNavBarToApp(WindowManagerService service,
- DisplayContent displayContent, @WindowManager.TransitionOldType int transit) {
- return (transit == TRANSIT_OLD_TASK_OPEN || transit == TRANSIT_OLD_TASK_TO_FRONT
- || transit == TRANSIT_OLD_WALLPAPER_CLOSE)
- && displayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
- && displayContent.getAsyncRotationController() == null;
- }
-
- /**
- * Creates and starts remote animations for all the visible non app windows.
- *
- * @return RemoteAnimationTarget[] targets for all the visible non app windows
- */
- private static void startNonAppWindowAnimationsForKeyguardExit(WindowManagerService service,
- long durationHint, long statusBarTransitionDelay,
- ArrayList<RemoteAnimationTarget> targets,
- ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
-
- final WindowManagerPolicy policy = service.mPolicy;
- service.mRoot.forAllWindows(nonAppWindow -> {
- // Animation on the IME window is controlled via Insets.
- if (nonAppWindow.mActivityRecord == null && nonAppWindow.canBeHiddenByKeyguard()
- && nonAppWindow.wouldBeVisibleIfPolicyIgnored() && !nonAppWindow.isVisible()
- && nonAppWindow != service.mRoot.getCurrentInputMethodWindow()) {
- final NonAppWindowAnimationAdapter nonAppAdapter = new NonAppWindowAnimationAdapter(
- nonAppWindow, durationHint, statusBarTransitionDelay);
- adaptersOut.add(nonAppAdapter);
- nonAppWindow.startAnimation(nonAppWindow.getPendingTransaction(),
- nonAppAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
- targets.add(nonAppAdapter.createRemoteAnimationTarget());
- }
- }, true /* traverseTopToBottom */);
- }
-
- /**
- * Creates and starts remote animation for the navigation bar windows.
- *
- * @return RemoteAnimationTarget[] targets for all the visible non app windows
- */
- private static void startNavigationBarWindowAnimation(DisplayContent displayContent,
- long durationHint, long statusBarTransitionDelay,
- ArrayList<RemoteAnimationTarget> targets,
- ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
- final WindowState navWindow = displayContent.getDisplayPolicy().getNavigationBar();
- final NonAppWindowAnimationAdapter nonAppAdapter = new NonAppWindowAnimationAdapter(
- navWindow.mToken, durationHint, statusBarTransitionDelay);
- adaptersOut.add(nonAppAdapter);
- navWindow.mToken.startAnimation(navWindow.mToken.getPendingTransaction(),
- nonAppAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
- targets.add(nonAppAdapter.createRemoteAnimationTarget());
- }
-
- /**
- * Create a remote animation target for this animation adapter.
- */
- RemoteAnimationTarget createRemoteAnimationTarget() {
- mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false,
- new Rect(), null, mWindowContainer.getPrefixOrderIndex(),
- mWindowContainer.getLastSurfacePosition(), mWindowContainer.getBounds(), null,
- mWindowContainer.getWindowConfiguration(), true, null, null, null, false,
- mWindowContainer.getWindowType());
- return mTarget;
- }
-
- @Override
- public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
- int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
- mCapturedLeash = animationLeash;
- mCapturedLeashFinishCallback = finishCallback;
- mLastAnimationType = type;
- }
-
- /**
- * @return the callback to call to clean up when the animation has finished.
- */
- SurfaceAnimator.OnAnimationFinishedCallback getLeashFinishedCallback() {
- return mCapturedLeashFinishCallback;
- }
-
- /**
- * @return the type of animation.
- */
- @SurfaceAnimator.AnimationType
- int getLastAnimationType() {
- return mLastAnimationType;
- }
-
- WindowContainer getWindowContainer() {
- return mWindowContainer;
- }
-
- @Override
- public long getDurationHint() {
- return mDurationHint;
- }
-
- @Override
- public long getStatusBarTransitionsStartTime() {
- return SystemClock.uptimeMillis() + mStatusBarTransitionDelay;
- }
-
- /**
- * @return the leash for this animation (only valid after the non app window surface animation
- * has started).
- */
- SurfaceControl getLeash() {
- return mCapturedLeash;
- }
-
- @Override
- public void onAnimationCancelled(SurfaceControl animationLeash) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationCancelled");
- }
-
- @Override
- public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix);
- pw.print("windowContainer=");
- pw.println(mWindowContainer);
- if (mTarget != null) {
- pw.print(prefix);
- pw.println("Target:");
- mTarget.dump(pw, prefix + " ");
- } else {
- pw.print(prefix);
- pw.println("Target: null");
- }
- }
-
- @Override
- public void dumpDebug(ProtoOutputStream proto) {
- final long token = proto.start(REMOTE);
- if (mTarget != null) {
- mTarget.dumpDebug(proto, TARGET);
- }
- proto.end(token);
- }
-}
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
deleted file mode 100644
index b3b2c57550e4..000000000000
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ /dev/null
@@ -1,636 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm;
-
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
-
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_REMOTE_ANIMATIONS;
-import static com.android.server.wm.AnimationAdapterProto.REMOTE;
-import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.annotation.ColorInt;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder.DeathRecipient;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-import android.view.IRemoteAnimationFinishedCallback;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-import android.view.WindowManager;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLog;
-import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.util.FastPrintWriter;
-import com.android.server.wm.SurfaceAnimator.AnimationType;
-import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.function.Consumer;
-
-/**
- * Helper class to run app animations in a remote process.
- */
-class RemoteAnimationController implements DeathRecipient {
- private static final String TAG = TAG_WITH_CLASS_NAME
- ? "RemoteAnimationController" : TAG_WM;
- private static final long TIMEOUT_MS = 10000;
-
- private final WindowManagerService mService;
- private final DisplayContent mDisplayContent;
- private final RemoteAnimationAdapter mRemoteAnimationAdapter;
- private final ArrayList<RemoteAnimationRecord> mPendingAnimations = new ArrayList<>();
- private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations =
- new ArrayList<>();
- @VisibleForTesting
- final ArrayList<NonAppWindowAnimationAdapter> mPendingNonAppAnimations = new ArrayList<>();
- private final Handler mHandler;
- private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable");
- private boolean mIsFinishing;
-
- private FinishedCallback mFinishedCallback;
- private final boolean mIsActivityEmbedding;
- private boolean mCanceled;
- private boolean mLinkedToDeathOfRunner;
- @Nullable
- private Runnable mOnRemoteAnimationReady;
-
- RemoteAnimationController(WindowManagerService service, DisplayContent displayContent,
- RemoteAnimationAdapter remoteAnimationAdapter, Handler handler,
- boolean isActivityEmbedding) {
- mService = service;
- mDisplayContent = displayContent;
- mRemoteAnimationAdapter = remoteAnimationAdapter;
- mHandler = handler;
- mIsActivityEmbedding = isActivityEmbedding;
- }
-
- /**
- * Creates an animation record for each individual {@link WindowContainer}.
- *
- * @param windowContainer The windows to animate.
- * @param position The position app bounds relative to its parent.
- * @param localBounds The bounds of the app relative to its parent.
- * @param endBounds The end bounds after the transition, in screen coordinates.
- * @param startBounds The start bounds before the transition, in screen coordinates.
- * @param showBackdrop To show background behind a window during animation.
- * @return The record representing animation(s) to run on the app.
- */
- RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
- Point position, Rect localBounds, Rect endBounds, Rect startBounds,
- boolean showBackdrop) {
- return createRemoteAnimationRecord(windowContainer, position, localBounds, endBounds,
- startBounds, showBackdrop, startBounds != null /* shouldCreateSnapshot */);
- }
-
- /**
- * Creates an animation record for each individual {@link WindowContainer}.
- *
- * @param windowContainer The windows to animate.
- * @param position The position app bounds relative to its parent.
- * @param localBounds The bounds of the app relative to its parent.
- * @param endBounds The end bounds after the transition, in screen coordinates.
- * @param startBounds The start bounds before the transition, in screen coordinates.
- * @param showBackdrop To show background behind a window during animation.
- * @param shouldCreateSnapshot Whether this target should create a snapshot animation.
- * @return The record representing animation(s) to run on the app.
- */
- RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
- Point position, Rect localBounds, Rect endBounds, Rect startBounds,
- boolean showBackdrop, boolean shouldCreateSnapshot) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
- windowContainer);
- final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position,
- localBounds, endBounds, startBounds, showBackdrop, shouldCreateSnapshot);
- mPendingAnimations.add(adapters);
- return adapters;
- }
-
- /** Sets callback to run before starting remote animation. */
- void setOnRemoteAnimationReady(@Nullable Runnable onRemoteAnimationReady) {
- mOnRemoteAnimationReady = onRemoteAnimationReady;
- }
-
- /**
- * We use isFromActivityEmbedding() in the server process to tell if we're running an
- * Activity Embedding type remote animation, where animations are driven by the client.
- * This is currently supporting features like showBackdrop where we need to load App XML.
- */
- public boolean isFromActivityEmbedding() {
- return mIsActivityEmbedding;
- }
-
- /**
- * Called when the transition is ready to be started, and all leashes have been set up.
- */
- void goodToGo(@WindowManager.TransitionOldType int transit) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo()");
- if (mCanceled) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
- "goodToGo(): Animation canceled already");
- onAnimationFinished();
- invokeAnimationCancelled("already_cancelled");
- return;
- }
-
- // Scale the timeout with the animator scale the controlling app is using.
- mHandler.postDelayed(mTimeoutRunnable,
- (long) (TIMEOUT_MS * mService.getCurrentAnimatorScale()));
- mFinishedCallback = new FinishedCallback(this);
-
- // Create the app targets
- final RemoteAnimationTarget[] appTargets = createAppAnimations();
- if (appTargets.length == 0 && !AppTransition.isKeyguardOccludeTransitOld(transit)) {
- // Keyguard occlude transition can be executed before the occluding activity becomes
- // visible. Even in this case, KeyguardService expects to receive binder call, so we
- // don't cancel remote animation.
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
- "goodToGo(): No apps to animate, mPendingAnimations=%d",
- mPendingAnimations.size());
- onAnimationFinished();
- invokeAnimationCancelled("no_app_targets");
- return;
- }
-
- if (mOnRemoteAnimationReady != null) {
- mOnRemoteAnimationReady.run();
- mOnRemoteAnimationReady = null;
- }
-
- // Create the remote wallpaper animation targets (if any)
- final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
-
- // Create the remote non app animation targets (if any)
- final RemoteAnimationTarget[] nonAppTargets = createNonAppWindowAnimations(transit);
-
- mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
- try {
- linkToDeathOfRunner();
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): onAnimationStart,"
- + " transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
- AppTransition.appTransitionOldToString(transit), appTargets.length,
- wallpaperTargets.length, nonAppTargets.length);
- if (AppTransition.isKeyguardOccludeTransitOld(transit)) {
- EventLogTags.writeWmSetKeyguardOccluded(
- transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE ? 0 : 1,
- 1 /* animate */,
- transit,
- "onAnimationStart");
- }
- mRemoteAnimationAdapter.getRunner().onAnimationStart(transit, appTargets,
- wallpaperTargets, nonAppTargets, mFinishedCallback);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to start remote animation", e);
- onAnimationFinished();
- }
- if (ProtoLog.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS, LogLevel.DEBUG)) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation(): Notify animation start:");
- writeStartDebugStatement();
- }
- });
- setRunningRemoteAnimation(true);
- }
-
- void cancelAnimation(String reason) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason);
- synchronized (mService.getWindowManagerLock()) {
- if (mCanceled) {
- return;
- }
- mCanceled = true;
- }
- onAnimationFinished();
- invokeAnimationCancelled(reason);
- }
-
- private void writeStartDebugStatement() {
- ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Starting remote animation");
- final StringWriter sw = new StringWriter();
- final FastPrintWriter pw = new FastPrintWriter(sw);
- for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
- mPendingAnimations.get(i).mAdapter.dump(pw, "");
- }
- pw.close();
- ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "%s", sw.toString());
- }
-
- private RemoteAnimationTarget[] createAppAnimations() {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAppAnimations()");
- final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
- for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
- final RemoteAnimationRecord wrappers = mPendingAnimations.get(i);
- final RemoteAnimationTarget target = wrappers.createRemoteAnimationTarget();
- if (target != null) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tAdd container=%s",
- wrappers.mWindowContainer);
- targets.add(target);
- } else {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tRemove container=%s",
- wrappers.mWindowContainer);
-
- // We can't really start an animation but we still need to make sure to finish the
- // pending animation that was started by SurfaceAnimator
- if (wrappers.mAdapter != null
- && wrappers.mAdapter.mCapturedFinishCallback != null) {
- wrappers.mAdapter.mCapturedFinishCallback
- .onAnimationFinished(wrappers.mAdapter.mAnimationType,
- wrappers.mAdapter);
- }
- if (wrappers.mThumbnailAdapter != null
- && wrappers.mThumbnailAdapter.mCapturedFinishCallback != null) {
- wrappers.mThumbnailAdapter.mCapturedFinishCallback
- .onAnimationFinished(wrappers.mThumbnailAdapter.mAnimationType,
- wrappers.mThumbnailAdapter);
- }
- mPendingAnimations.remove(i);
- }
- }
- return targets.toArray(new RemoteAnimationTarget[targets.size()]);
- }
-
- private RemoteAnimationTarget[] createWallpaperAnimations() {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createWallpaperAnimations()");
- return WallpaperAnimationAdapter.startWallpaperAnimations(mDisplayContent,
- mRemoteAnimationAdapter.getDuration(),
- mRemoteAnimationAdapter.getStatusBarTransitionDelay(),
- adapter -> {
- synchronized (mService.mGlobalLock) {
- // If the wallpaper animation is canceled, continue with the app animation
- mPendingWallpaperAnimations.remove(adapter);
- }
- }, mPendingWallpaperAnimations);
- }
-
- private RemoteAnimationTarget[] createNonAppWindowAnimations(
- @WindowManager.TransitionOldType int transit) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createNonAppWindowAnimations()");
- return NonAppWindowAnimationAdapter.startNonAppWindowAnimations(mService,
- mDisplayContent,
- transit,
- mRemoteAnimationAdapter.getDuration(),
- mRemoteAnimationAdapter.getStatusBarTransitionDelay(),
- mPendingNonAppAnimations);
- }
-
- private void onAnimationFinished() {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationFinished(): mPendingAnimations=%d",
- mPendingAnimations.size());
- mHandler.removeCallbacks(mTimeoutRunnable);
- synchronized (mService.mGlobalLock) {
- mIsFinishing = true;
- unlinkToDeathOfRunner();
- releaseFinishedCallback();
- try {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
- "onAnimationFinished(): Notify animation finished:");
- for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
- final RemoteAnimationRecord adapters = mPendingAnimations.get(i);
- if (adapters.mAdapter != null) {
- adapters.mAdapter.mCapturedFinishCallback
- .onAnimationFinished(adapters.mAdapter.mAnimationType,
- adapters.mAdapter);
- }
- if (adapters.mThumbnailAdapter != null) {
- adapters.mThumbnailAdapter.mCapturedFinishCallback
- .onAnimationFinished(adapters.mThumbnailAdapter.mAnimationType,
- adapters.mThumbnailAdapter);
- }
- mPendingAnimations.remove(i);
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tcontainer=%s",
- adapters.mWindowContainer);
- }
-
- for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
- final WallpaperAnimationAdapter adapter = mPendingWallpaperAnimations.get(i);
- adapter.getLeashFinishedCallback().onAnimationFinished(
- adapter.getLastAnimationType(), adapter);
- mPendingWallpaperAnimations.remove(i);
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\twallpaper=%s", adapter.getToken());
- }
-
- for (int i = mPendingNonAppAnimations.size() - 1; i >= 0; i--) {
- final NonAppWindowAnimationAdapter adapter = mPendingNonAppAnimations.get(i);
- adapter.getLeashFinishedCallback().onAnimationFinished(
- adapter.getLastAnimationType(), adapter);
- mPendingNonAppAnimations.remove(i);
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tnonApp=%s",
- adapter.getWindowContainer());
- }
- } catch (Exception e) {
- Slog.e(TAG, "Failed to finish remote animation", e);
- throw e;
- } finally {
- mIsFinishing = false;
- }
- // Reset input for all activities when the remote animation is finished.
- final Consumer<ActivityRecord> updateActivities =
- activity -> activity.setDropInputForAnimation(false);
- mDisplayContent.forAllActivities(updateActivities);
- }
- setRunningRemoteAnimation(false);
- ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation");
- }
-
- private void invokeAnimationCancelled(String reason) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason);
- try {
- mRemoteAnimationAdapter.getRunner().onAnimationCancelled();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to notify cancel", e);
- }
- mOnRemoteAnimationReady = null;
- }
-
- private void releaseFinishedCallback() {
- if (mFinishedCallback != null) {
- mFinishedCallback.release();
- mFinishedCallback = null;
- }
- }
-
- private void setRunningRemoteAnimation(boolean running) {
- final int pid = mRemoteAnimationAdapter.getCallingPid();
- final int uid = mRemoteAnimationAdapter.getCallingUid();
-
- if (pid == 0) {
- throw new RuntimeException("Calling pid of remote animation was null");
- }
- final WindowProcessController wpc = mService.mAtmService.getProcessController(pid, uid);
- if (wpc == null) {
- Slog.w(TAG, "Unable to find process with pid=" + pid + " uid=" + uid);
- return;
- }
- wpc.setRunningRemoteAnimation(running);
- }
-
- private void linkToDeathOfRunner() throws RemoteException {
- if (!mLinkedToDeathOfRunner) {
- mRemoteAnimationAdapter.getRunner().asBinder().linkToDeath(this, 0);
- mLinkedToDeathOfRunner = true;
- }
- }
-
- private void unlinkToDeathOfRunner() {
- if (mLinkedToDeathOfRunner) {
- mRemoteAnimationAdapter.getRunner().asBinder().unlinkToDeath(this, 0);
- mLinkedToDeathOfRunner = false;
- }
- }
-
- @Override
- public void binderDied() {
- cancelAnimation("binderDied");
- }
-
- private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub {
-
- RemoteAnimationController mOuter;
-
- FinishedCallback(RemoteAnimationController outer) {
- mOuter = outer;
- }
-
- @Override
- public void onAnimationFinished() throws RemoteException {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-onAnimationFinished(): mOuter=%s", mOuter);
- final long token = Binder.clearCallingIdentity();
- try {
- if (mOuter != null) {
- mOuter.onAnimationFinished();
-
- // In case the client holds on to the finish callback, make sure we don't leak
- // RemoteAnimationController which in turn would leak the runner on the client.
- mOuter = null;
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Marks this callback as not be used anymore by releasing the reference to the outer class
- * to prevent memory leak.
- */
- void release() {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-release(): mOuter=%s", mOuter);
- mOuter = null;
- }
- };
-
- /**
- * Contains information about a remote-animation for one WindowContainer. This keeps track of,
- * potentially, multiple animating surfaces (AdapterWrappers) associated with one
- * Window/Transition. For example, a change transition has an adapter controller for the
- * main window and an adapter controlling the start-state snapshot.
- * <p>
- * This can be thought of as a bridge between the information that the remote animator sees (via
- * {@link RemoteAnimationTarget}) and what the server sees (the
- * {@link RemoteAnimationAdapterWrapper}(s) interfacing with the moving surfaces).
- */
- public class RemoteAnimationRecord {
- RemoteAnimationAdapterWrapper mAdapter;
- RemoteAnimationAdapterWrapper mThumbnailAdapter = null;
- RemoteAnimationTarget mTarget;
- final WindowContainer mWindowContainer;
- final Rect mStartBounds;
- final boolean mShowBackdrop;
- @ColorInt int mBackdropColor = 0;
- private @RemoteAnimationTarget.Mode int mMode = RemoteAnimationTarget.MODE_CHANGING;
-
- RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds,
- Rect endBounds, @Nullable Rect startBounds, boolean showBackdrop,
- boolean shouldCreateSnapshot) {
- mWindowContainer = windowContainer;
- mShowBackdrop = showBackdrop;
- if (startBounds != null) {
- mStartBounds = new Rect(startBounds);
- mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
- mStartBounds, mShowBackdrop);
- if (shouldCreateSnapshot && mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
- final Rect thumbnailLocalBounds = new Rect(startBounds);
- thumbnailLocalBounds.offsetTo(0, 0);
- // Snapshot is located at (0,0) of the animation leash. It doesn't have size
- // change, so the startBounds is its end bounds, and no start bounds for it.
- mThumbnailAdapter = new RemoteAnimationAdapterWrapper(this, new Point(0, 0),
- thumbnailLocalBounds, startBounds, new Rect(), mShowBackdrop);
- }
- } else {
- mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
- new Rect(), mShowBackdrop);
- mStartBounds = null;
- }
- }
-
- void setBackDropColor(@ColorInt int backdropColor) {
- mBackdropColor = backdropColor;
- }
-
- RemoteAnimationTarget createRemoteAnimationTarget() {
- if (mAdapter == null
- || mAdapter.mCapturedFinishCallback == null
- || mAdapter.mCapturedLeash == null) {
- return null;
- }
- mTarget = mWindowContainer.createRemoteAnimationTarget(this);
- return mTarget;
- }
-
- void setMode(@RemoteAnimationTarget.Mode int mode) {
- mMode = mode;
- }
-
- int getMode() {
- return mMode;
- }
-
- /** Whether its parent is also an animation target in the same transition. */
- boolean hasAnimatingParent() {
- // mOpeningApps and mClosingApps are only activities, so only need to check
- // mChangingContainers.
- for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) {
- if (mWindowContainer.isDescendantOf(
- mDisplayContent.mChangingContainers.valueAt(i))) {
- return true;
- }
- }
- return false;
- }
- }
-
- class RemoteAnimationAdapterWrapper implements AnimationAdapter {
- private final RemoteAnimationRecord mRecord;
- SurfaceControl mCapturedLeash;
- private OnAnimationFinishedCallback mCapturedFinishCallback;
- private @AnimationType int mAnimationType;
- final Point mPosition = new Point();
- final Rect mLocalBounds;
- final Rect mEndBounds = new Rect();
- final Rect mStartBounds = new Rect();
- final boolean mShowBackdrop;
-
- RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
- Rect localBounds, Rect endBounds, Rect startBounds, boolean showBackdrop) {
- mRecord = record;
- mPosition.set(position.x, position.y);
- mLocalBounds = localBounds;
- mEndBounds.set(endBounds);
- mStartBounds.set(startBounds);
- mShowBackdrop = showBackdrop;
- }
-
- @Override
- @ColorInt
- public int getBackgroundColor() {
- return mRecord.mBackdropColor;
- }
-
- @Override
- public boolean getShowBackground() {
- return mShowBackdrop;
- }
-
- @Override
- public boolean getShowWallpaper() {
- return false;
- }
-
- @Override
- public void startAnimation(SurfaceControl animationLeash, Transaction t,
- @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
-
- if (mStartBounds.isEmpty()) {
- // Restore position and stack crop until client has a chance to modify it.
- t.setPosition(animationLeash, mPosition.x, mPosition.y);
- t.setWindowCrop(animationLeash, mEndBounds.width(), mEndBounds.height());
- } else {
- // Offset the change animation leash to the relative start position in parent.
- // (mPosition) is the relative end position in parent container.
- // (mStartBounds - mEndBounds) is the position difference between start and end.
- // (mPosition + mStartBounds - mEndBounds) will be the relative start position.
- t.setPosition(animationLeash, mPosition.x + mStartBounds.left - mEndBounds.left,
- mPosition.y + mStartBounds.top - mEndBounds.top);
- t.setWindowCrop(animationLeash, mStartBounds.width(), mStartBounds.height());
- }
- mCapturedLeash = animationLeash;
- mCapturedFinishCallback = finishCallback;
- mAnimationType = type;
- }
-
- @Override
- public void onAnimationCancelled(SurfaceControl animationLeash) {
- if (mIsFinishing) {
- return;
- }
- if (mRecord.mAdapter == this) {
- mRecord.mAdapter = null;
- } else {
- mRecord.mThumbnailAdapter = null;
- }
- if (mRecord.mAdapter == null && mRecord.mThumbnailAdapter == null) {
- mPendingAnimations.remove(mRecord);
- }
- if (mPendingAnimations.isEmpty()) {
- cancelAnimation("allAppAnimationsCanceled");
- }
- }
-
- @Override
- public long getDurationHint() {
- return mRemoteAnimationAdapter.getDuration();
- }
-
- @Override
- public long getStatusBarTransitionsStartTime() {
- return SystemClock.uptimeMillis()
- + mRemoteAnimationAdapter.getStatusBarTransitionDelay();
- }
-
- @Override
- public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.print("container="); pw.println(mRecord.mWindowContainer);
- if (mRecord.mTarget != null) {
- pw.print(prefix); pw.println("Target:");
- mRecord.mTarget.dump(pw, prefix + " ");
- } else {
- pw.print(prefix); pw.println("Target: null");
- }
- }
-
- @Override
- public void dumpDebug(ProtoOutputStream proto) {
- final long token = proto.start(REMOTE);
- if (mRecord.mTarget != null) {
- mRecord.mTarget.dumpDebug(proto, TARGET);
- }
- proto.end(token);
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3abab8bf62c2..bf9883c76a06 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -166,6 +166,7 @@ import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.window.DesktopExperienceFlags;
import android.window.DesktopModeFlags;
import android.window.ITaskOrganizer;
import android.window.PictureInPictureSurfaceTransaction;
@@ -2378,7 +2379,7 @@ class Task extends TaskFragment {
// configurations and let its parent (organized task) to control it;
final Task rootTask = getRootTask();
boolean shouldInheritBounds = rootTask != this && rootTask.isOrganized();
- if (Flags.enableMultipleDesktopsBackend()) {
+ if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) {
// Only inherit from organized parent when this task is not organized.
shouldInheritBounds &= !isOrganized();
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index ae3a015a690d..1966ecf57c73 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -50,7 +50,6 @@ import android.graphics.Color;
import android.os.UserHandle;
import android.util.IntArray;
import android.util.Slog;
-import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -776,13 +775,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
return needsZBoost[0];
}
- @Override
- RemoteAnimationTarget createRemoteAnimationTarget(
- RemoteAnimationController.RemoteAnimationRecord record) {
- final ActivityRecord activity = getTopMostActivity();
- return activity != null ? activity.createRemoteAnimationTarget(record) : null;
- }
-
void setBackgroundColor(@ColorInt int colorInt) {
setBackgroundColor(colorInt, false /* restore */);
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 97a1a34336e9..74059c1cc9b1 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -99,7 +99,6 @@ import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
-import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
import android.window.TaskFragmentAnimationParams;
@@ -2306,18 +2305,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
@Override
- RemoteAnimationTarget createRemoteAnimationTarget(
- RemoteAnimationController.RemoteAnimationRecord record) {
- final ActivityRecord activity = record.getMode() == RemoteAnimationTarget.MODE_OPENING
- // There may be a launching (e.g. trampoline or embedded) activity without a window
- // on top of the existing task which is moving to front. Exclude finishing activity
- // so the window of next activity can be chosen to create the animation target.
- ? getActivity(r -> !r.finishing && r.hasChild())
- : getTopMostActivity();
- return activity != null ? activity.createRemoteAnimationTarget(record) : null;
- }
-
- @Override
boolean canCreateRemoteAnimationTarget() {
return true;
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index fe653e454d6c..5217a759c6ae 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -36,7 +36,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -974,10 +973,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
return false;
}
- boolean isInAodAppearTransition() {
- return (mFlags & TRANSIT_FLAG_AOD_APPEARING) != 0;
- }
-
/**
* Specifies configuration change explicitly for the window container, so it can be chosen as
* transition target. This is usually used with transition mode
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 25b513d85384..ba7f36419ac5 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -525,19 +525,6 @@ class TransitionController {
return false;
}
- boolean isInAodAppearTransition() {
- if (mCollectingTransition != null && mCollectingTransition.isInAodAppearTransition()) {
- return true;
- }
- for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) {
- if (mWaitingTransitions.get(i).isInAodAppearTransition()) return true;
- }
- for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
- if (mPlayingTransitions.get(i).isInAodAppearTransition()) return true;
- }
- return false;
- }
-
/**
* @return A pair of the transition and restore-behind target for the given {@param container}.
* @param container An ancestor of a transient-launch activity
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
deleted file mode 100644
index c3e85b1f8662..000000000000
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm;
-
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_REMOTE_ANIMATIONS;
-import static com.android.server.wm.AnimationAdapterProto.REMOTE;
-import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
-
-import android.annotation.NonNull;
-import android.graphics.Point;
-import android.os.SystemClock;
-import android.util.proto.ProtoOutputStream;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-
-import com.android.internal.protolog.ProtoLog;
-import com.android.server.wm.SurfaceAnimator.AnimationType;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.function.Consumer;
-
-/**
- * An animation adapter for wallpaper windows.
- */
-class WallpaperAnimationAdapter implements AnimationAdapter {
- private static final String TAG = "WallpaperAnimationAdapter";
-
- private final WallpaperWindowToken mWallpaperToken;
- private SurfaceControl mCapturedLeash;
- private SurfaceAnimator.OnAnimationFinishedCallback mCapturedLeashFinishCallback;
- private @AnimationType int mLastAnimationType;
-
- private long mDurationHint;
- private long mStatusBarTransitionDelay;
-
- private Consumer<WallpaperAnimationAdapter> mAnimationCanceledRunnable;
- private RemoteAnimationTarget mTarget;
-
- WallpaperAnimationAdapter(WallpaperWindowToken wallpaperToken,
- long durationHint, long statusBarTransitionDelay,
- Consumer<WallpaperAnimationAdapter> animationCanceledRunnable) {
- mWallpaperToken = wallpaperToken;
- mDurationHint = durationHint;
- mStatusBarTransitionDelay = statusBarTransitionDelay;
- mAnimationCanceledRunnable = animationCanceledRunnable;
- }
-
- /**
- * Creates and starts remote animations for all the visible wallpaper windows.
- *
- * @return RemoteAnimationTarget[] targets for all the visible wallpaper windows
- */
- public static RemoteAnimationTarget[] startWallpaperAnimations(DisplayContent displayContent,
- long durationHint, long statusBarTransitionDelay,
- Consumer<WallpaperAnimationAdapter> animationCanceledRunnable,
- ArrayList<WallpaperAnimationAdapter> adaptersOut) {
- if (!shouldStartWallpaperAnimation(displayContent)) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
- "\tWallpaper of display=%s is not visible", displayContent);
- return new RemoteAnimationTarget[0];
- }
- final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
- displayContent.forAllWallpaperWindows(wallpaperWindow -> {
- final WallpaperAnimationAdapter wallpaperAdapter = new WallpaperAnimationAdapter(
- wallpaperWindow, durationHint, statusBarTransitionDelay,
- animationCanceledRunnable);
- wallpaperWindow.startAnimation(wallpaperWindow.getPendingTransaction(),
- wallpaperAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
- targets.add(wallpaperAdapter.createRemoteAnimationTarget());
- adaptersOut.add(wallpaperAdapter);
- });
- return targets.toArray(new RemoteAnimationTarget[targets.size()]);
- }
-
- static boolean shouldStartWallpaperAnimation(DisplayContent displayContent) {
- return displayContent.mWallpaperController.isWallpaperVisible();
- }
-
- /**
- * Create a remote animation target for this animation adapter.
- */
- RemoteAnimationTarget createRemoteAnimationTarget() {
- mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false, null, null,
- mWallpaperToken.getPrefixOrderIndex(), new Point(), null, null,
- mWallpaperToken.getWindowConfiguration(), true, null, null, null, false);
- return mTarget;
- }
-
- /**
- * @return the leash for this animation (only valid after the wallpaper window surface animation
- * has started).
- */
- SurfaceControl getLeash() {
- return mCapturedLeash;
- }
-
- /**
- * @return the callback to call to clean up when the animation has finished.
- */
- SurfaceAnimator.OnAnimationFinishedCallback getLeashFinishedCallback() {
- return mCapturedLeashFinishCallback;
- }
-
- /**
- * @return the type of animation.
- */
- @AnimationType int getLastAnimationType() {
- return mLastAnimationType;
- }
-
- /**
- * @return the wallpaper window
- */
- WallpaperWindowToken getToken() {
- return mWallpaperToken;
- }
-
- @Override
- public boolean getShowWallpaper() {
- // Not used
- return false;
- }
-
- @Override
- public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
- @AnimationType int type,
- @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
-
- // Restore z-layering until client has a chance to modify it.
- t.setLayer(animationLeash, mWallpaperToken.getPrefixOrderIndex());
- mCapturedLeash = animationLeash;
- mCapturedLeashFinishCallback = finishCallback;
- mLastAnimationType = type;
- }
-
- @Override
- public void onAnimationCancelled(SurfaceControl animationLeash) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationCancelled");
- mAnimationCanceledRunnable.accept(this);
- }
-
- @Override
- public long getDurationHint() {
- return mDurationHint;
- }
-
- @Override
- public long getStatusBarTransitionsStartTime() {
- return SystemClock.uptimeMillis() + mStatusBarTransitionDelay;
- }
-
- @Override
- public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix);
- pw.print("token=");
- pw.println(mWallpaperToken);
- if (mTarget != null) {
- pw.print(prefix);
- pw.println("Target:");
- mTarget.dump(pw, prefix + " ");
- } else {
- pw.print(prefix);
- pw.println("Target: null");
- }
- }
-
- @Override
- public void dumpDebug(ProtoOutputStream proto) {
- final long token = proto.start(REMOTE);
- if (mTarget != null) {
- mTarget.dumpDebug(proto, TARGET);
- }
- proto.end(token);
- }
-}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 70948e1264c4..c1ef208d1d4d 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -166,14 +166,6 @@ class WallpaperController {
mFindResults.setWallpaperTarget(w);
return false;
}
- } else if (mService.mFlags.mAodTransition
- && mDisplayContent.isKeyguardLockedOrAodShowing()) {
- if (mService.mPolicy.isKeyguardHostWindow(w.mAttrs)
- && w.mTransitionController.isInAodAppearTransition()) {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Found aod transition wallpaper target: " + w);
- mFindResults.setWallpaperTarget(w);
- return true;
- }
}
final boolean animationWallpaper = animatingContainer != null
@@ -692,8 +684,7 @@ class WallpaperController {
private WallpaperWindowToken getTokenForTarget(WindowState target) {
if (target == null) return null;
WindowState window = mFindResults.getTopWallpaper(
- (target.canShowWhenLocked() && mService.isKeyguardLocked())
- || (mService.mFlags.mAodTransition && mDisplayContent.isAodShowing()));
+ target.canShowWhenLocked() && mService.isKeyguardLocked());
return window == null ? null : window.mToken.asWallpaperToken();
}
@@ -736,9 +727,7 @@ class WallpaperController {
if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) {
mFindResults.setWallpaperTarget(
- mFindResults.getTopWallpaper(mService.mFlags.mAodTransition
- ? mDisplayContent.isKeyguardLockedOrAodShowing()
- : mDisplayContent.isKeyguardLocked()));
+ mFindResults.getTopWallpaper(mDisplayContent.isKeyguardLocked()));
}
}
@@ -910,17 +899,11 @@ class WallpaperController {
if (mDisplayContent.mWmService.mFlags.mEnsureWallpaperInTransitions) {
visibleRequested = mWallpaperTarget != null && mWallpaperTarget.isVisibleRequested();
}
- updateWallpaperTokens(visibleRequested,
- mService.mFlags.mAodTransition
- ? mDisplayContent.isKeyguardLockedOrAodShowing()
- : mDisplayContent.isKeyguardLocked());
+ updateWallpaperTokens(visibleRequested, mDisplayContent.isKeyguardLocked());
ProtoLog.v(WM_DEBUG_WALLPAPER,
"Wallpaper at display %d - visibility: %b, keyguardLocked: %b",
- mDisplayContent.getDisplayId(), visible,
- mService.mFlags.mAodTransition
- ? mDisplayContent.isKeyguardLockedOrAodShowing()
- : mDisplayContent.isKeyguardLocked());
+ mDisplayContent.getDisplayId(), visible, mDisplayContent.isKeyguardLocked());
if (visible && mLastFrozen != mFindResults.isWallpaperTargetForLetterbox) {
mLastFrozen = mFindResults.isWallpaperTargetForLetterbox;
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 3b79c54f1c73..7c88abcec7ec 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -34,7 +34,6 @@ import android.util.SparseArray;
import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
-import java.util.function.Consumer;
/**
* A token that represents a set of wallpaper windows.
@@ -250,11 +249,6 @@ class WallpaperWindowToken extends WindowToken {
}
@Override
- void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) {
- callback.accept(this);
- }
-
- @Override
boolean fillsParent() {
return true;
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 7af542f10127..95cdf46ea488 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -97,7 +97,6 @@ import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.MagnificationSpec;
import android.view.RemoteAnimationDefinition;
-import android.view.RemoteAnimationTarget;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
@@ -303,7 +302,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* This gets used during some open/close transitions as well as during a change transition
* where it represents the starting-state snapshot.
*/
- WindowContainerThumbnail mThumbnail;
final Point mTmpPoint = new Point();
protected final Rect mTmpRect = new Rect();
final Rect mTmpPrevBounds = new Rect();
@@ -2097,12 +2095,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
}
- void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- mChildren.get(i).forAllWallpaperWindows(callback);
- }
- }
-
/**
* Calls the given {@param callback} for all tasks in depth-first top-down z-order at or below
* this container.
@@ -3174,61 +3166,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
getAnimationPosition(mTmpPoint);
mTmpRect.offsetTo(0, 0);
- final AppTransition appTransition = getDisplayContent().mAppTransition;
- final RemoteAnimationController controller = appTransition.getRemoteAnimationController();
final boolean isChanging = AppTransition.isChangeTransitOld(transit) && enter
&& isChangingAppTransition();
- if (controller != null) {
- // Here we load App XML in order to read com.android.R.styleable#Animation_showBackdrop.
- boolean showBackdrop = false;
- // Optionally set backdrop color if App explicitly provides it through
- // {@link Activity#overridePendingTransition(int, int, int)}.
- @ColorInt int backdropColor = 0;
- if (controller.isFromActivityEmbedding()) {
- if (isChanging) {
- // When there are more than one changing containers, it may leave part of the
- // screen empty. Show background color to cover that.
- showBackdrop = getDisplayContent().mChangingContainers.size() > 1;
- backdropColor = appTransition.getNextAppTransitionBackgroundColor();
- } else {
- // Check whether the app has requested to show backdrop for open/close
- // transition.
- final Animation a = appTransition.getNextAppRequestedAnimation(enter);
- if (a != null) {
- showBackdrop = a.getShowBackdrop();
- backdropColor = a.getBackdropColor();
- }
- }
- }
- final Rect localBounds = new Rect(mTmpRect);
- localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
- final RemoteAnimationController.RemoteAnimationRecord adapters;
- if (!isChanging && !enter && isClosingWhenResizing()) {
- // Container that is closing while resizing. Pass in the closing start bounds, so
- // the animation can start with the correct bounds, there won't be a snapshot.
- // Cleanup the mClosingChangingContainers so that when the animation is finished, it
- // will reset the surface.
- final Rect closingStartBounds = getDisplayContent().mClosingChangingContainers
- .remove(this);
- adapters = controller.createRemoteAnimationRecord(
- this, mTmpPoint, localBounds, screenBounds, closingStartBounds,
- showBackdrop, false /* shouldCreateSnapshot */);
- } else {
- final Rect startBounds = null;
- adapters = controller.createRemoteAnimationRecord(
- this, mTmpPoint, localBounds, screenBounds, startBounds, showBackdrop);
- }
- if (backdropColor != 0) {
- adapters.setBackDropColor(backdropColor);
- }
- if (!isChanging) {
- adapters.setMode(enter
- ? RemoteAnimationTarget.MODE_OPENING
- : RemoteAnimationTarget.MODE_CLOSING);
- }
- resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
- } else if (isChanging) {
+ if (isChanging) {
final float durationScale = mWmService.getTransitionAnimationScaleLocked();
final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
@@ -3417,11 +3358,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return a;
}
- RemoteAnimationTarget createRemoteAnimationTarget(
- RemoteAnimationController.RemoteAnimationRecord record) {
- return null;
- }
-
boolean canCreateRemoteAnimationTarget() {
return false;
}
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
deleted file mode 100644
index ae477e1e22f0..000000000000
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2017 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.wm;
-
-import static android.view.SurfaceControl.METADATA_OWNER_UID;
-import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
-
-import static com.android.internal.protolog.WmProtoLogGroups.WM_SHOW_TRANSACTIONS;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
-import static com.android.server.wm.WindowContainerThumbnailProto.HEIGHT;
-import static com.android.server.wm.WindowContainerThumbnailProto.SURFACE_ANIMATOR;
-import static com.android.server.wm.WindowContainerThumbnailProto.WIDTH;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
-
-import android.graphics.ColorSpace;
-import android.graphics.GraphicBuffer;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.hardware.HardwareBuffer;
-import android.util.proto.ProtoOutputStream;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Builder;
-import android.view.SurfaceControl.Transaction;
-import android.view.animation.Animation;
-
-import com.android.internal.protolog.ProtoLog;
-import com.android.server.wm.SurfaceAnimator.Animatable;
-import com.android.server.wm.SurfaceAnimator.AnimationType;
-
-/**
- * Represents a surface that is displayed over a subclass of {@link WindowContainer}
- */
-class WindowContainerThumbnail implements Animatable {
-
- private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainerThumbnail" : TAG_WM;
-
- private final WindowContainer mWindowContainer;
- private SurfaceControl mSurfaceControl;
- private final SurfaceAnimator mSurfaceAnimator;
- private final int mWidth;
- private final int mHeight;
-
- /**
- * @param t Transaction to create the thumbnail in.
- * @param container The sub-class of {@link WindowContainer} to associate this thumbnail with.
- * @param thumbnailHeader A thumbnail or placeholder for thumbnail to initialize with.
- */
- WindowContainerThumbnail(Transaction t, WindowContainer container,
- HardwareBuffer thumbnailHeader) {
- this(t, container, thumbnailHeader, null /* animator */);
- }
-
- WindowContainerThumbnail(Transaction t, WindowContainer container,
- HardwareBuffer thumbnailHeader, SurfaceAnimator animator) {
- mWindowContainer = container;
- if (animator != null) {
- mSurfaceAnimator = animator;
- } else {
- // We can't use a delegating constructor since we need to
- // reference this::onAnimationFinished
- mSurfaceAnimator =
- new SurfaceAnimator(this, this::onAnimationFinished /* animationFinishedCallback */,
- container.mWmService);
- }
- mWidth = thumbnailHeader.getWidth();
- mHeight = thumbnailHeader.getHeight();
-
- // Create a new surface for the thumbnail
- // TODO: This should be attached as a child to the app token, once the thumbnail animations
- // use relative coordinates. Once we start animating task we can also consider attaching
- // this to the task.
- mSurfaceControl = mWindowContainer.makeChildSurface(mWindowContainer.getTopChild())
- .setName("thumbnail anim: " + mWindowContainer.toString())
- .setBLASTLayer()
- .setFormat(PixelFormat.TRANSLUCENT)
- .setMetadata(METADATA_WINDOW_TYPE, mWindowContainer.getWindowingMode())
- .setMetadata(METADATA_OWNER_UID, WindowManagerService.MY_UID)
- .setCallsite("WindowContainerThumbnail")
- .build();
-
- ProtoLog.i(WM_SHOW_TRANSACTIONS, " THUMBNAIL %s: CREATE", mSurfaceControl);
-
- GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(thumbnailHeader);
- t.setBuffer(mSurfaceControl, graphicBuffer);
- t.setColorSpace(mSurfaceControl, ColorSpace.get(ColorSpace.Named.SRGB));
- t.show(mSurfaceControl);
-
- // We parent the thumbnail to the container, and just place it on top of anything else in
- // the container.
- t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
- }
-
- void startAnimation(Transaction t, Animation anim) {
- startAnimation(t, anim, null /* position */);
- }
-
- void startAnimation(Transaction t, Animation anim, Point position) {
- anim.restrictDuration(MAX_ANIMATION_DURATION);
- anim.scaleCurrentDuration(mWindowContainer.mWmService.getTransitionAnimationScaleLocked());
- mSurfaceAnimator.startAnimation(t, new LocalAnimationAdapter(
- new WindowAnimationSpec(anim, position,
- mWindowContainer.getDisplayContent().mAppTransition.canSkipFirstFrame(),
- mWindowContainer.getDisplayContent().getWindowCornerRadius()),
- mWindowContainer.mWmService.mSurfaceAnimationRunner), false /* hidden */,
- ANIMATION_TYPE_APP_TRANSITION);
- }
-
- private void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
- }
-
- void setShowing(Transaction pendingTransaction, boolean show) {
- // TODO: Not needed anymore once thumbnail is attached to the app.
- if (show) {
- pendingTransaction.show(mSurfaceControl);
- } else {
- pendingTransaction.hide(mSurfaceControl);
- }
- }
-
- void destroy() {
- mSurfaceAnimator.cancelAnimation();
- getPendingTransaction().remove(mSurfaceControl);
- mSurfaceControl = null;
- }
-
- /**
- * Write to a protocol buffer output stream. Protocol buffer message definition is at {@link
- * com.android.server.wm.WindowContainerThumbnailProto}.
- *
- * @param proto Stream to write the WindowContainerThumbnailProto object to.
- * @param fieldId Field Id of the WindowContainerThumbnailProto as defined in the parent
- * message.
- * @hide
- */
- void dumpDebug(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
- proto.write(WIDTH, mWidth);
- proto.write(HEIGHT, mHeight);
- if (mSurfaceAnimator.isAnimating()) {
- mSurfaceAnimator.dumpDebug(proto, SURFACE_ANIMATOR);
- }
- proto.end(token);
- }
-
- @Override
- public Transaction getSyncTransaction() {
- return mWindowContainer.getSyncTransaction();
- }
-
- @Override
- public Transaction getPendingTransaction() {
- return mWindowContainer.getPendingTransaction();
- }
-
- @Override
- public void commitPendingTransaction() {
- mWindowContainer.commitPendingTransaction();
- }
-
- @Override
- public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
- t.setLayer(leash, Integer.MAX_VALUE);
- }
-
- @Override
- public void onAnimationLeashLost(Transaction t) {
-
- // TODO: Once attached to app token, we don't need to hide it immediately if thumbnail
- // became visible.
- t.hide(mSurfaceControl);
- }
-
- @Override
- public Builder makeAnimationLeash() {
- return mWindowContainer.makeChildSurface(mWindowContainer.getTopChild());
- }
-
- @Override
- public SurfaceControl getSurfaceControl() {
- return mSurfaceControl;
- }
-
- @Override
- public SurfaceControl getAnimationLeashParent() {
- return mWindowContainer.getAnimationLeashParent();
- }
-
- @Override
- public SurfaceControl getParentSurfaceControl() {
- return mWindowContainer.getParentSurfaceControl();
- }
-
- @Override
- public int getSurfaceWidth() {
- return mWidth;
- }
-
- @Override
- public int getSurfaceHeight() {
- return mHeight;
- }
-}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 3b6a4dc6e1b0..4c53ba53a506 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -30,24 +30,25 @@ import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_F
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_PRIVILEGED_REORDER_TO_BOTTOM_OF_TASK;
+import static android.window.TaskFragmentOperation.OP_TYPE_PRIVILEGED_REORDER_TO_TOP_OF_TASK;
+import static android.window.TaskFragmentOperation.OP_TYPE_PRIVILEGED_SET_CAN_AFFECT_SYSTEM_UI_FLAGS;
+import static android.window.TaskFragmentOperation.OP_TYPE_PRIVILEGED_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH;
import static android.window.TaskFragmentOperation.OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE;
-import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_BOTTOM_OF_TASK;
import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT;
-import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_TOP_OF_TASK;
import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
-import static android.window.TaskFragmentOperation.OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_DECOR_SURFACE_BOOSTED;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_DIM_ON_TASK;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ISOLATED_NAVIGATION;
-import static android.window.TaskFragmentOperation.OP_TYPE_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_PINNED;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_RELATIVE_BOUNDS;
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_UNKNOWN;
+import static android.window.TaskFragmentOperation.PRIVILEGED_OP_START;
import static android.window.WindowContainerTransaction.Change.CHANGE_FOCUSABLE;
import static android.window.WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT;
import static android.window.WindowContainerTransaction.Change.CHANGE_HIDDEN;
@@ -1786,7 +1787,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
taskFragment.setIsolatedNav(isolatedNav);
break;
}
- case OP_TYPE_REORDER_TO_BOTTOM_OF_TASK: {
+ case OP_TYPE_PRIVILEGED_REORDER_TO_BOTTOM_OF_TASK: {
final Task task = taskFragment.getTask();
if (task != null) {
if (task.getBottomChild() != taskFragment) {
@@ -1802,7 +1803,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
break;
}
- case OP_TYPE_REORDER_TO_TOP_OF_TASK: {
+ case OP_TYPE_PRIVILEGED_REORDER_TO_TOP_OF_TASK: {
final Task task = taskFragment.getTask();
if (task != null) {
if (task.getTopChild() != taskFragment) {
@@ -1852,7 +1853,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
: EMBEDDED_DIM_AREA_TASK_FRAGMENT);
break;
}
- case OP_TYPE_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH: {
+ case OP_TYPE_PRIVILEGED_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH: {
taskFragment.setMoveToBottomIfClearWhenLaunch(operation.getBooleanValue());
break;
}
@@ -1888,7 +1889,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
taskFragment.setPinned(pinned);
break;
}
- case OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS: {
+ case OP_TYPE_PRIVILEGED_SET_CAN_AFFECT_SYSTEM_UI_FLAGS: {
taskFragment.setCanAffectSystemUiFlags(operation.getBooleanValue());
// Request to apply the flags.
@@ -1938,45 +1939,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return false;
}
final int opType = operation.getOpType();
- if (opType == OP_TYPE_CREATE_TASK_FRAGMENT) {
- // No need to check TaskFragment.
- return true;
- }
-
- if (!validateTaskFragment(taskFragment, opType, errorCallbackToken, organizer)) {
- return false;
- }
- if ((opType == OP_TYPE_REORDER_TO_BOTTOM_OF_TASK
- || opType == OP_TYPE_REORDER_TO_TOP_OF_TASK)
+ if (opType >= PRIVILEGED_OP_START
&& !mTaskFragmentOrganizerController.isSystemOrganizer(organizer.asBinder())) {
final Throwable exception = new SecurityException(
- "Only a system organizer can perform OP_TYPE_REORDER_TO_BOTTOM_OF_TASK or "
- + "OP_TYPE_REORDER_TO_TOP_OF_TASK."
+ "Only a system organizer can perform privileged operations. opType=" + opType
);
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
opType, exception);
return false;
}
- if ((opType == OP_TYPE_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH)
- && !mTaskFragmentOrganizerController.isSystemOrganizer(organizer.asBinder())) {
- final Throwable exception = new SecurityException(
- "Only a system organizer can perform "
- + "OP_TYPE_SET_MOVE_TO_BOTTOM_IF_CLEAR_WHEN_LAUNCH."
- );
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
- opType, exception);
- return false;
+ if (opType == OP_TYPE_CREATE_TASK_FRAGMENT) {
+ // No need to check TaskFragment.
+ return true;
}
- if ((opType == OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS)
- && !mTaskFragmentOrganizerController.isSystemOrganizer(organizer.asBinder())) {
- final Throwable exception = new SecurityException(
- "Only a system organizer can perform OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS."
- );
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
- opType, exception);
+ if (!validateTaskFragment(taskFragment, opType, errorCallbackToken, organizer)) {
return false;
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index f07e6722d836..0d0c0bad24fa 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -124,6 +124,7 @@ static struct {
jmethodID notifyStylusGestureStarted;
jmethodID notifyVibratorState;
jmethodID filterInputEvent;
+ jmethodID filterPointerMotion;
jmethodID interceptKeyBeforeQueueing;
jmethodID interceptMotionBeforeQueueingNonInteractive;
jmethodID interceptKeyBeforeDispatching;
@@ -451,6 +452,8 @@ public:
void notifyPointerDisplayIdChanged(ui::LogicalDisplayId displayId,
const vec2& position) override;
void notifyMouseCursorFadedOnTyping() override;
+ std::optional<vec2> filterPointerMotionForAccessibility(
+ const vec2& current, const vec2& delta, const ui::LogicalDisplayId& displayId) override;
/* --- InputFilterPolicyInterface implementation --- */
void notifyStickyModifierStateChanged(uint32_t modifierState,
@@ -938,6 +941,27 @@ void NativeInputManager::notifyStickyModifierStateChanged(uint32_t modifierState
checkAndClearExceptionFromCallback(env, "notifyStickyModifierStateChanged");
}
+std::optional<vec2> NativeInputManager::filterPointerMotionForAccessibility(
+ const vec2& current, const vec2& delta, const ui::LogicalDisplayId& displayId) {
+ JNIEnv* env = jniEnv();
+ ScopedFloatArrayRO filtered(env,
+ jfloatArray(
+ env->CallObjectMethod(mServiceObj,
+ gServiceClassInfo.filterPointerMotion,
+ delta.x, delta.y, current.x,
+ current.y, displayId.val())));
+ if (checkAndClearExceptionFromCallback(env, "filterPointerMotionForAccessibilityLocked")) {
+ ALOGE("Disabling accessibility pointer motion filter due to an error. "
+ "The filter state in Java and PointerChoreographer would no longer be in sync.");
+ return std::nullopt;
+ }
+ LOG_ALWAYS_FATAL_IF(filtered.size() != 2,
+ "Accessibility pointer motion filter is misbehaving. Returned array size "
+ "%zu should be 2.",
+ filtered.size());
+ return vec2{filtered[0], filtered[1]};
+}
+
sp<SurfaceControl> NativeInputManager::getParentSurfaceForPointers(ui::LogicalDisplayId displayId) {
JNIEnv* env = jniEnv();
jlong nativeSurfaceControlPtr =
@@ -3271,6 +3295,12 @@ static jboolean nativeSetKernelWakeEnabled(JNIEnv* env, jobject nativeImplObj, j
return im->getInputManager()->getReader().setKernelWakeEnabled(deviceId, enabled);
}
+static void nativeSetAccessibilityPointerMotionFilterEnabled(JNIEnv* env, jobject nativeImplObj,
+ jboolean enabled) {
+ NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+ im->getInputManager()->getChoreographer().setAccessibilityPointerMotionFilterEnabled(enabled);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gInputManagerMethods[] = {
@@ -3398,6 +3428,8 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"setInputMethodConnectionIsActive", "(Z)V", (void*)nativeSetInputMethodConnectionIsActive},
{"getLastUsedInputDeviceId", "()I", (void*)nativeGetLastUsedInputDeviceId},
{"setKernelWakeEnabled", "(IZ)Z", (void*)nativeSetKernelWakeEnabled},
+ {"setAccessibilityPointerMotionFilterEnabled", "(Z)V",
+ (void*)nativeSetAccessibilityPointerMotionFilterEnabled},
};
#define FIND_CLASS(var, className) \
@@ -3482,6 +3514,8 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
"filterInputEvent", "(Landroid/view/InputEvent;I)Z");
+ GET_METHOD_ID(gServiceClassInfo.filterPointerMotion, clazz, "filterPointerMotion", "(FFFFI)[F");
+
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
"interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index b9f00d7979c2..44a83541f0b9 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -16,6 +16,8 @@
package com.android.server.people;
+import static com.android.server.flags.Flags.earlyDataManagerInit;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -117,6 +119,18 @@ public class PeopleService extends SystemService {
}
@Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_BOOT_COMPLETED) {
+ if (earlyDataManagerInit()) {
+ // Force initialization of DataManager before onUserUnlocked
+ // to avoid blocking the ActivityManagerService on
+ // shortcutHandleUnlockUser.
+ getDataManager();
+ }
+ }
+ }
+
+ @Override
public void onUserUnlocked(@NonNull TargetUser user) {
getDataManager().onUserUnlocked(user.getUserIdentifier());
}
diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java
index a96c477c78d2..f731b50d81b4 100644
--- a/services/supervision/java/com/android/server/supervision/SupervisionService.java
+++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java
@@ -17,6 +17,8 @@
package com.android.server.supervision;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.MANAGE_USERS;
+import static android.Manifest.permission.QUERY_USERS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.Preconditions.checkCallAuthorization;
@@ -79,6 +81,25 @@ public class SupervisionService extends ISupervisionManager.Stub {
}
/**
+ * Creates an {@link Intent} that can be used with {@link Context#startActivity(Intent)} to
+ * launch the activity to verify supervision credentials.
+ *
+ * <p>A valid {@link Intent} is always returned if supervision is enabled at the time this
+ * method is called, the launched activity still need to perform validity checks as the
+ * supervision state can change when it's launched. A null intent is returned if supervision is
+ * disabled at the time of this method call.
+ *
+ * <p>A result code of {@link android.app.Activity#RESULT_OK} indicates successful verification
+ * of the supervision credentials.
+ */
+ @Override
+ @Nullable
+ public Intent createConfirmSupervisionCredentialsIntent() {
+ // TODO(b/392961554): Implement createAuthenticationIntent API
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Returns whether supervision is enabled for the given user.
*
* <p>Supervision is automatically enabled when the supervision app becomes the profile owner or
@@ -86,6 +107,7 @@ public class SupervisionService extends ISupervisionManager.Stub {
*/
@Override
public boolean isSupervisionEnabledForUser(@UserIdInt int userId) {
+ enforceAnyPermission(QUERY_USERS, MANAGE_USERS);
if (UserHandle.getUserId(Binder.getCallingUid()) != userId) {
enforcePermission(INTERACT_ACROSS_USERS);
}
@@ -96,6 +118,7 @@ public class SupervisionService extends ISupervisionManager.Stub {
@Override
public void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled) {
+ // TODO(b/395630828): Ensure that this method can only be called by the system.
if (UserHandle.getUserId(Binder.getCallingUid()) != userId) {
enforcePermission(INTERACT_ACROSS_USERS);
}
@@ -181,8 +204,8 @@ public class SupervisionService extends ISupervisionManager.Stub {
* Ensures that supervision is enabled when the supervision app is the profile owner.
*
* <p>The state syncing with the DevicePolicyManager can only enable supervision and never
- * disable. Supervision can only be disabled explicitly via calls to the
- * {@link #setSupervisionEnabledForUser} method.
+ * disable. Supervision can only be disabled explicitly via calls to the {@link
+ * #setSupervisionEnabledForUser} method.
*/
private void syncStateWithDevicePolicyManager(@UserIdInt int userId) {
final DevicePolicyManagerInternal dpmInternal = mInjector.getDpmInternal();
@@ -221,6 +244,17 @@ public class SupervisionService extends ISupervisionManager.Stub {
mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED);
}
+ /** Enforces that the caller has at least one of the given permission. */
+ private void enforceAnyPermission(String... permissions) {
+ boolean authorized = false;
+ for (String permission : permissions) {
+ if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ authorized = true;
+ }
+ }
+ checkCallAuthorization(authorized);
+ }
+
/** Provides local services in a lazy manner. */
static class Injector {
private final Context mContext;
@@ -280,7 +314,7 @@ public class SupervisionService extends ISupervisionManager.Stub {
}
@VisibleForTesting
- @SuppressLint("MissingPermission") // not needed for a system service
+ @SuppressLint("MissingPermission")
void registerProfileOwnerListener() {
IntentFilter poIntentFilter = new IntentFilter();
poIntentFilter.addAction(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED);
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml
index b7de74987eb8..45523268c966 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml
@@ -32,8 +32,8 @@
<uses-library android:name="android.test.runner" />
</application>
- <!-- The "targetPackage" reference the instruments APK package, which is the FakeImeApk, while
- the test package is "com.android.inputmethod.imetests" (FrameworksImeTests.apk).-->
+ <!-- The "targetPackage" reference the instruments APK package, which is the SimpleTestIme.apk,
+ while the test package is "com.android.inputmethod.imetests" (FrameworksImeTests.apk).-->
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.apps.inputmethod.simpleime"
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 72e9cc566497..2d3f7231cc5c 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -34,12 +34,12 @@ import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import android.app.ActivityManager;
import android.app.Instrumentation;
import android.content.res.Configuration;
import android.graphics.Insets;
+import android.os.Build;
import android.os.RemoteException;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.server.wm.WindowManagerStateHelper;
@@ -86,22 +86,36 @@ public class InputMethodServiceTest {
"android:id/input_method_nav_back";
private static final String INPUT_METHOD_NAV_IME_SWITCHER_ID =
"android:id/input_method_nav_ime_switcher";
- private static final long TIMEOUT_IN_SECONDS = 3;
- private static final String ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD =
- "settings put secure " + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD + " 1";
- private static final String DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD =
- "settings put secure " + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD + " 0";
- private final WindowManagerStateHelper mWmState = new WindowManagerStateHelper();
+ /** Timeout until the uiObject should be found. */
+ private static final long TIMEOUT_MS = 5000L * Build.HW_TIMEOUT_MULTIPLIER;
+
+ /** Timeout until the event is expected. */
+ private static final long EXPECT_TIMEOUT_MS = 3000L * Build.HW_TIMEOUT_MULTIPLIER;
+
+ /** Timeout during which the event is not expected. */
+ private static final long NOT_EXCEPT_TIMEOUT_MS = 2000L * Build.HW_TIMEOUT_MULTIPLIER;
+
+ /** Command to set showing the IME when a hardware keyboard is connected. */
+ private static final String SET_SHOW_IME_WITH_HARD_KEYBOARD_CMD =
+ "settings put secure " + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD;
+ /** Command to get verbose ImeTracker logging state. */
+ private static final String GET_VERBOSE_IME_TRACKER_LOGGING_CMD =
+ "getprop persist.debug.imetracker";
+ /** Command to set verbose ImeTracker logging state. */
+ private static final String SET_VERBOSE_IME_TRACKER_LOGGING_CMD =
+ "setprop persist.debug.imetracker";
+
+ /** The ids of the subtypes of SimpleIme. */
+ private static final int[] SUBTYPE_IDS = new int[]{1, 2};
+
+ private final WindowManagerStateHelper mWmState = new WindowManagerStateHelper();
private final GestureNavSwitchHelper mGestureNavSwitchHelper = new GestureNavSwitchHelper();
private final DeviceFlagsValueProvider mFlagsValueProvider = new DeviceFlagsValueProvider();
@Rule
- public final CheckFlagsRule mCheckFlagsRule = new CheckFlagsRule(mFlagsValueProvider);
-
- @Rule
public final TestName mName = new TestName();
private Instrumentation mInstrumentation;
@@ -111,7 +125,8 @@ public class InputMethodServiceTest {
private String mInputMethodId;
private TestActivity mActivity;
private InputMethodServiceWrapper mInputMethodService;
- private boolean mShowImeWithHardKeyboardEnabled;
+ private boolean mOriginalVerboseImeTrackerLoggingEnabled;
+ private boolean mOriginalShowImeWithHardKeyboardEnabled;
@Before
public void setUp() throws Exception {
@@ -120,9 +135,12 @@ public class InputMethodServiceTest {
mImm = mInstrumentation.getContext().getSystemService(InputMethodManager.class);
mTargetPackageName = mInstrumentation.getTargetContext().getPackageName();
mInputMethodId = getInputMethodId();
+ mOriginalVerboseImeTrackerLoggingEnabled = getVerboseImeTrackerLogging();
+ if (!mOriginalVerboseImeTrackerLoggingEnabled) {
+ setVerboseImeTrackerLogging(true);
+ }
prepareIme();
prepareActivity();
- mInstrumentation.waitForIdleSync();
mUiDevice.freezeRotation();
mUiDevice.setOrientationNatural();
// Waits for input binding ready.
@@ -145,17 +163,18 @@ public class InputMethodServiceTest {
.that(mInputMethodService.getCurrentInputViewStarted()).isFalse();
});
// Save the original value of show_ime_with_hard_keyboard from Settings.
- mShowImeWithHardKeyboardEnabled =
+ mOriginalShowImeWithHardKeyboardEnabled =
mInputMethodService.getShouldShowImeWithHardKeyboardForTesting();
}
@After
public void tearDown() throws Exception {
mUiDevice.unfreezeRotation();
+ if (!mOriginalVerboseImeTrackerLoggingEnabled) {
+ setVerboseImeTrackerLogging(false);
+ }
// Change back the original value of show_ime_with_hard_keyboard in Settings.
- executeShellCommand(mShowImeWithHardKeyboardEnabled
- ? ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD
- : DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD);
+ setShowImeWithHardKeyboard(mOriginalShowImeWithHardKeyboardEnabled);
executeShellCommand("ime disable " + mInputMethodId);
}
@@ -167,21 +186,20 @@ public class InputMethodServiceTest {
public void testShowHideKeyboard_byUserAction() {
waitUntilActivityReadyForInputInjection(mActivity);
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
// Performs click on EditText to bring up the IME.
Log.i(TAG, "Click on EditText");
verifyInputViewStatus(
() -> clickOnViewCenter(mActivity.getEditText()),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
// Press home key to hide IME.
Log.i(TAG, "Press home");
if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
assertWithMessage("Home key press was handled").that(mUiDevice.pressHome()).isTrue();
+ // This doesn't call verifyInputViewStatus, as the refactor delays the events such that
+ // getCurrentInputStarted() would be false, as we would already be in launcher.
// The IME visibility is only sent at the end of the animation. Therefore, we have to
// wait until the visibility was sent to the server and the IME window hidden.
eventually(() -> assertWithMessage("IME is not shown")
@@ -190,11 +208,7 @@ public class InputMethodServiceTest {
verifyInputViewStatus(
() -> assertWithMessage("Home key press was handled")
.that(mUiDevice.pressHome()).isTrue(),
- EVENT_HIDE,
- true /* expected */,
- false /* inputViewStarted */);
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
+ EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown");
}
}
@@ -203,31 +217,15 @@ public class InputMethodServiceTest {
*/
@Test
public void testShowHideKeyboard_byInputMethodManager() {
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
- // Triggers to show IME via public API.
verifyInputViewStatusOnMainSync(
() -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
- // Triggers to hide IME via public API.
verifyInputViewStatusOnMainSync(
() -> assertThat(mActivity.hideImeWithInputMethodManager(0 /* flags */)).isTrue(),
- EVENT_HIDE,
- true /* expected */,
- false /* inputViewStarted */);
- if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // The IME visibility is only sent at the end of the animation. Therefore, we have to
- // wait until the visibility was sent to the server and the IME window hidden.
- eventually(() -> assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse());
- } else {
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
- }
+ EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown");
}
/**
@@ -235,105 +233,31 @@ public class InputMethodServiceTest {
*/
@Test
public void testShowHideKeyboard_byInsetsController() {
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
- // Triggers to show IME via public API.
verifyInputViewStatusOnMainSync(
() -> mActivity.showImeWithWindowInsetsController(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
- // Triggers to hide IME via public API.
verifyInputViewStatusOnMainSync(
() -> mActivity.hideImeWithWindowInsetsController(),
- EVENT_HIDE,
- true /* expected */,
- false /* inputViewStarted */);
- if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // The IME visibility is only sent at the end of the animation. Therefore, we have to
- // wait until the visibility was sent to the server and the IME window hidden.
- eventually(() -> assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse());
- } else {
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
- }
+ EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown");
}
/**
* This checks the result of calling IMS#requestShowSelf and IMS#requestHideSelf.
- *
- * <p>With the refactor in b/298172246, all calls to IMMS#{show,hide}MySoftInputLocked
- * will be just apply the requested visibility (by using the callback). Therefore, we will
- * lose flags like HIDE_IMPLICIT_ONLY.
*/
@Test
public void testShowHideSelf() {
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
- // IME request to show itself without any flags, expect shown.
- Log.i(TAG, "Call IMS#requestShowSelf(0)");
verifyInputViewStatusOnMainSync(
() -> mInputMethodService.requestShowSelf(0 /* flags */),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
-
- if (!mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // IME request to hide itself with flag HIDE_IMPLICIT_ONLY, expect not hide (shown).
- Log.i(TAG, "Call IMS#requestHideSelf(InputMethodManager.HIDE_IMPLICIT_ONLY)");
- verifyInputViewStatusOnMainSync(
- () -> mInputMethodService.requestHideSelf(
- InputMethodManager.HIDE_IMPLICIT_ONLY),
- EVENT_HIDE,
- false /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is still shown after HIDE_IMPLICIT_ONLY")
- .that(mInputMethodService.isInputViewShown()).isTrue();
- }
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
- // IME request to hide itself without any flags, expect hidden.
- Log.i(TAG, "Call IMS#requestHideSelf(0)");
verifyInputViewStatusOnMainSync(
() -> mInputMethodService.requestHideSelf(0 /* flags */),
- EVENT_HIDE,
- true /* expected */,
- false /* inputViewStarted */);
- if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // The IME visibility is only sent at the end of the animation. Therefore, we have to
- // wait until the visibility was sent to the server and the IME window hidden.
- eventually(() -> assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse());
- } else {
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
- }
-
- if (!mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // IME request to show itself with flag SHOW_IMPLICIT, expect shown.
- Log.i(TAG, "Call IMS#requestShowSelf(InputMethodManager.SHOW_IMPLICIT)");
- verifyInputViewStatusOnMainSync(
- () -> mInputMethodService.requestShowSelf(InputMethodManager.SHOW_IMPLICIT),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown with SHOW_IMPLICIT")
- .that(mInputMethodService.isInputViewShown()).isTrue();
-
- // IME request to hide itself with flag HIDE_IMPLICIT_ONLY, expect hidden.
- Log.i(TAG, "Call IMS#requestHideSelf(InputMethodManager.HIDE_IMPLICIT_ONLY)");
- verifyInputViewStatusOnMainSync(
- () -> mInputMethodService.requestHideSelf(
- InputMethodManager.HIDE_IMPLICIT_ONLY),
- EVENT_HIDE,
- true /* expected */,
- false /* inputViewStarted */);
- assertWithMessage("IME is not shown after HIDE_IMPLICIT_ONLY")
- .that(mInputMethodService.isInputViewShown()).isFalse();
- }
+ EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown");
}
/**
@@ -342,28 +266,25 @@ public class InputMethodServiceTest {
*/
@Test
public void testOnEvaluateInputViewShown_showImeWithHardKeyboard() {
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
final var config = mInputMethodService.getResources().getConfiguration();
final var initialConfig = new Configuration(config);
try {
config.keyboard = Configuration.KEYBOARD_QWERTY;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
- eventually(() ->
- assertWithMessage("InputView should show with visible hardware keyboard")
- .that(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+ assertWithMessage("InputView should show with visible hardware keyboard")
+ .that(mInputMethodService.onEvaluateInputViewShown()).isTrue();
config.keyboard = Configuration.KEYBOARD_NOKEYS;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
- eventually(() ->
- assertWithMessage("InputView should show without hardware keyboard")
- .that(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+ assertWithMessage("InputView should show without hardware keyboard")
+ .that(mInputMethodService.onEvaluateInputViewShown()).isTrue();
config.keyboard = Configuration.KEYBOARD_QWERTY;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
- eventually(() ->
- assertWithMessage("InputView should show with hidden hardware keyboard")
- .that(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+ assertWithMessage("InputView should show with hidden hardware keyboard")
+ .that(mInputMethodService.onEvaluateInputViewShown()).isTrue();
} finally {
mInputMethodService.getResources()
.updateConfiguration(initialConfig, null /* metrics */, null /* compat */);
@@ -376,28 +297,25 @@ public class InputMethodServiceTest {
*/
@Test
public void testOnEvaluateInputViewShown_disableShowImeWithHardKeyboard() {
- setShowImeWithHardKeyboard(false /* enabled */);
+ setShowImeWithHardKeyboard(false /* enable */);
final var config = mInputMethodService.getResources().getConfiguration();
final var initialConfig = new Configuration(config);
try {
config.keyboard = Configuration.KEYBOARD_QWERTY;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
- eventually(() ->
- assertWithMessage("InputView should not show with visible hardware keyboard")
- .that(mInputMethodService.onEvaluateInputViewShown()).isFalse());
+ assertWithMessage("InputView should not show with visible hardware keyboard")
+ .that(mInputMethodService.onEvaluateInputViewShown()).isFalse();
config.keyboard = Configuration.KEYBOARD_NOKEYS;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
- eventually(() ->
- assertWithMessage("InputView should show without hardware keyboard")
- .that(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+ assertWithMessage("InputView should show without hardware keyboard")
+ .that(mInputMethodService.onEvaluateInputViewShown()).isTrue();
config.keyboard = Configuration.KEYBOARD_QWERTY;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
- eventually(() ->
- assertWithMessage("InputView should show with hidden hardware keyboard")
- .that(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+ assertWithMessage("InputView should show with hidden hardware keyboard")
+ .that(mInputMethodService.onEvaluateInputViewShown()).isTrue();
} finally {
mInputMethodService.getResources()
.updateConfiguration(initialConfig, null /* metrics */, null /* compat */);
@@ -410,7 +328,7 @@ public class InputMethodServiceTest {
*/
@Test
public void testShowSoftInput_disableShowImeWithHardKeyboard() {
- setShowImeWithHardKeyboard(false /* enabled */);
+ setShowImeWithHardKeyboard(false /* enable */);
final var config = mInputMethodService.getResources().getConfiguration();
final var initialConfig = new Configuration(config);
@@ -424,20 +342,14 @@ public class InputMethodServiceTest {
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(
InputMethodManager.SHOW_IMPLICIT)).isTrue(),
- EVENT_SHOW,
- false /* expected */,
- false /* inputViewStarted */);
- assertWithMessage("IME is not shown after SHOW_IMPLICIT")
- .that(mInputMethodService.isInputViewShown()).isFalse();
+ EVENT_SHOW, false /* eventExpected */, false /* shown */,
+ "IME is not shown after SHOW_IMPLICIT");
verifyInputViewStatusOnMainSync(
() -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */))
.isTrue(),
- EVENT_SHOW,
- false /* expected */,
- false /* inputViewStarted */);
- assertWithMessage("IME is not shown after SHOW_EXPLICIT")
- .that(mInputMethodService.isInputViewShown()).isFalse();
+ EVENT_SHOW, false /* eventExpected */, false /* shown */,
+ "IME is not shown after SHOW_EXPLICIT");
} finally {
mInputMethodService.getResources()
.updateConfiguration(initialConfig, null /* metrics */, null /* compat */);
@@ -445,56 +357,18 @@ public class InputMethodServiceTest {
}
/**
- * This checks that an explicit show request results in the IME being shown.
- */
- @Test
- public void testShowSoftInputExplicitly() {
- setShowImeWithHardKeyboard(true /* enabled */);
-
- // When InputMethodService#onEvaluateInputViewShown() returns true and flag is EXPLICIT, the
- // IME should be shown.
- verifyInputViewStatusOnMainSync(
- () -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
- }
-
- /**
- * This checks that an implicit show request results in the IME being shown.
- */
- @Test
- public void testShowSoftInputImplicitly() {
- setShowImeWithHardKeyboard(true /* enabled */);
-
- // When InputMethodService#onEvaluateInputViewShown() returns true and flag is IMPLICIT,
- // the IME should be shown.
- verifyInputViewStatusOnMainSync(() -> assertThat(
- mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
- }
-
- /**
* This checks that an explicit show request when the IME is not previously shown,
* and it should be shown in fullscreen mode, results in the IME being shown.
*/
@Test
public void testShowSoftInputExplicitly_fullScreenMode() {
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
// Set orientation landscape to enable fullscreen mode.
setOrientation(2);
- eventually(() -> assertWithMessage("No longer in natural orientation")
- .that(mUiDevice.isNaturalOrientation()).isFalse());
- // Wait for the TestActivity to be recreated.
eventually(() -> assertWithMessage("Activity was re-created after rotation")
- .that(TestActivity.getLastCreatedInstance()).isNotEqualTo(mActivity));
- // Get the new TestActivity.
- mActivity = TestActivity.getLastCreatedInstance();
+ .that(TestActivity.getInstance()).isNotEqualTo(mActivity));
+ mActivity = TestActivity.getInstance();
assertWithMessage("Re-created activity is not null").that(mActivity).isNotNull();
// Wait for the new EditText to be served by InputMethodManager.
eventually(() -> assertWithMessage("Has an input connection to the re-created Activity")
@@ -502,46 +376,45 @@ public class InputMethodServiceTest {
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
}
/**
* This checks that an implicit show request when the IME is not previously shown,
- * and it should be shown in fullscreen mode, results in the IME not being shown.
+ * and it should be shown in fullscreen mode behaves like an explicit show request, resulting
+ * in the IME being shown. This is due to the refactor in b/298172246, causing us to lose flag
+ * information like {@link InputMethodManager#SHOW_IMPLICIT}.
*
- * <p>With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput
- * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like
- * SHOW_IMPLICIT.
+ * <p>Previously, an implicit show request when the IME is not previously shown,
+ * and it should be shown in fullscreen mode, would result in the IME not being shown.
*/
@Test
- @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)
public void testShowSoftInputImplicitly_fullScreenMode() {
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
// Set orientation landscape to enable fullscreen mode.
setOrientation(2);
- eventually(() -> assertWithMessage("No longer in natural orientation")
- .that(mUiDevice.isNaturalOrientation()).isFalse());
- // Wait for the TestActivity to be recreated.
eventually(() -> assertWithMessage("Activity was re-created after rotation")
- .that(TestActivity.getLastCreatedInstance()).isNotEqualTo(mActivity));
- // Get the new TestActivity.
- mActivity = TestActivity.getLastCreatedInstance();
+ .that(TestActivity.getInstance()).isNotEqualTo(mActivity));
+ mActivity = TestActivity.getInstance();
assertWithMessage("Re-created activity is not null").that(mActivity).isNotNull();
// Wait for the new EditText to be served by InputMethodManager.
eventually(() -> assertWithMessage("Has an input connection to the re-created Activity")
.that(mImm.hasActiveInputConnection(mActivity.getEditText())).isTrue());
- verifyInputViewStatusOnMainSync(() -> assertThat(
- mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
- EVENT_SHOW,
- false /* expected */,
- false /* inputViewStarted */);
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(
+ InputMethodManager.SHOW_IMPLICIT))
+ .isTrue(),
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ } else {
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(
+ InputMethodManager.SHOW_IMPLICIT))
+ .isTrue(),
+ EVENT_SHOW, false /* eventExpected */, false /* shown */, "IME is not shown");
+ }
}
/**
@@ -550,7 +423,7 @@ public class InputMethodServiceTest {
*/
@Test
public void testShowSoftInputExplicitly_withHardKeyboard() {
- setShowImeWithHardKeyboard(false /* enabled */);
+ setShowImeWithHardKeyboard(false /* enable */);
final var config = mInputMethodService.getResources().getConfiguration();
final var initialConfig = new Configuration(config);
@@ -561,10 +434,7 @@ public class InputMethodServiceTest {
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
} finally {
mInputMethodService.getResources()
.updateConfiguration(initialConfig, null /* metrics */, null /* compat */);
@@ -572,17 +442,17 @@ public class InputMethodServiceTest {
}
/**
- * This checks that an implicit show request when a hardware keyboard is connected,
- * results in the IME not being shown.
+ * This checks that an implicit show request when a hardware keyboard is connected behaves
+ * like an explicit show request, resulting in the IME being shown. This is due to the
+ * refactor in b/298172246, causing us to lose flag information like
+ * {@link InputMethodManager#SHOW_IMPLICIT}.
*
- * <p>With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput
- * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like
- * SHOW_IMPLICIT.
+ * <p>Previously, an implicit show request when a hardware keyboard is connected would
+ * result in the IME not being shown.
*/
@Test
- @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)
public void testShowSoftInputImplicitly_withHardKeyboard() {
- setShowImeWithHardKeyboard(false /* enabled */);
+ setShowImeWithHardKeyboard(false /* enable */);
final var config = mInputMethodService.getResources().getConfiguration();
final var initialConfig = new Configuration(config);
@@ -591,14 +461,20 @@ public class InputMethodServiceTest {
config.keyboard = Configuration.KEYBOARD_QWERTY;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
- verifyInputViewStatusOnMainSync(() ->assertThat(
- mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT))
- .isTrue(),
- EVENT_SHOW,
- false /* expected */,
- false /* inputViewStarted */);
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(
+ InputMethodManager.SHOW_IMPLICIT))
+ .isTrue(),
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ } else {
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(
+ InputMethodManager.SHOW_IMPLICIT))
+ .isTrue(),
+ EVENT_SHOW, false /* eventExpected */, false /* shown */,
+ "IME is not shown");
+ }
} finally {
mInputMethodService.getResources()
.updateConfiguration(initialConfig, null /* metrics */, null /* compat */);
@@ -611,7 +487,7 @@ public class InputMethodServiceTest {
*/
@Test
public void testShowSoftInputExplicitly_thenConfigurationChanged() {
- setShowImeWithHardKeyboard(false /* enabled */);
+ setShowImeWithHardKeyboard(false /* enable */);
final var config = mInputMethodService.getResources().getConfiguration();
final var initialConfig = new Configuration(config);
@@ -623,10 +499,7 @@ public class InputMethodServiceTest {
verifyInputViewStatusOnMainSync(
() -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */))
.isTrue(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
// Simulate connecting a hardware keyboard.
config.keyboard = Configuration.KEYBOARD_QWERTY;
@@ -637,11 +510,8 @@ public class InputMethodServiceTest {
verifyInputViewStatusOnMainSync(
() -> mInputMethodService.onConfigurationChanged(config),
- EVENT_CONFIG,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is still shown after a configuration change")
- .that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_CONFIG, true /* eventExpected */, true /* shown */,
+ "IME is still shown after a configuration change");
} finally {
mInputMethodService.getResources()
.updateConfiguration(initialConfig, null /* metrics */, null /* compat */);
@@ -650,17 +520,17 @@ public class InputMethodServiceTest {
/**
* This checks that an implicit show request followed by connecting a hardware keyboard
- * and a configuration change, does not trigger IMS#onFinishInputView,
- * but results in the IME being hidden.
+ * and a configuration change behaves like an explicit show request, resulting in the IME
+ * still being shown. This is due to the refactor in b/298172246, causing us to lose flag
+ * information like {@link InputMethodManager#SHOW_IMPLICIT}.
*
- * <p>With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput
- * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like
- * SHOW_IMPLICIT.
+ * <p>Previously, an implicit show request followed by connecting a hardware keyboard
+ * and a configuration change, would not trigger IMS#onFinishInputView, but resulted in the
+ * IME being hidden.
*/
@Test
- @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)
public void testShowSoftInputImplicitly_thenConfigurationChanged() {
- setShowImeWithHardKeyboard(false /* enabled */);
+ setShowImeWithHardKeyboard(false /* enable */);
final var config = mInputMethodService.getResources().getConfiguration();
final var initialConfig = new Configuration(config);
@@ -672,10 +542,7 @@ public class InputMethodServiceTest {
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(
InputMethodManager.SHOW_IMPLICIT)).isTrue(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
// Simulate connecting a hardware keyboard.
config.keyboard = Configuration.KEYBOARD_QWERTY;
@@ -684,19 +551,23 @@ public class InputMethodServiceTest {
// Simulate a fake configuration change to avoid the recreation of TestActivity.
config.orientation = Configuration.ORIENTATION_LANDSCAPE;
- // Normally, IMS#onFinishInputView will be called when finishing the input view by
- // the user. But if IMS#hideWindow is called when receiving a new configuration change,
- // we don't expect that it's user-driven to finish the lifecycle of input view with
- // IMS#onFinishInputView, because the input view will be re-initialized according
- // to the last #mShowInputRequested state. So in this case we treat the input view as
- // still alive.
- verifyInputViewStatusOnMainSync(
- () -> mInputMethodService.onConfigurationChanged(config),
- EVENT_CONFIG,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is not shown after a configuration change")
- .that(mInputMethodService.isInputViewShown()).isFalse();
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ verifyInputViewStatusOnMainSync(
+ () -> mInputMethodService.onConfigurationChanged(config),
+ EVENT_CONFIG, true /* eventExpected */, true /* shown */,
+ "IME is still shown after a configuration change");
+ } else {
+ // Normally, IMS#onFinishInputView will be called when finishing the input view by
+ // the user. But if IMS#hideWindow is called when receiving a new configuration
+ // change, we don't expect that it's user-driven to finish the lifecycle of input
+ // view with IMS#onFinishInputView, because the input view will be re-initialized
+ // according to the last #mShowInputRequested state. So in this case we treat the
+ // input view as still alive.
+ verifyInputViewStatusOnMainSync(
+ () -> mInputMethodService.onConfigurationChanged(config),
+ EVENT_CONFIG, true /* eventExpected */, true /* inputViewStarted */,
+ false /* shown */, "IME is not shown after a configuration change");
+ }
} finally {
mInputMethodService.getResources()
.updateConfiguration(initialConfig, null /* metrics */, null /* compat */);
@@ -710,7 +581,7 @@ public class InputMethodServiceTest {
*/
@Test
public void testShowSoftInputExplicitly_thenShowSoftInputImplicitly_withHardKeyboard() {
- setShowImeWithHardKeyboard(false /* enabled */);
+ setShowImeWithHardKeyboard(false /* enable */);
final var config = mInputMethodService.getResources().getConfiguration();
final var initialConfig = new Configuration(config);
@@ -719,34 +590,22 @@ public class InputMethodServiceTest {
config.keyboard = Configuration.KEYBOARD_QWERTY;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
- // Explicit show request.
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
- // Implicit show request.
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(
InputMethodManager.SHOW_IMPLICIT)).isTrue(),
- EVENT_SHOW,
- false /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is still shown")
- .that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, false /* eventExpected */, true /* shown */, "IME is still shown");
// Simulate a fake configuration change to avoid the recreation of TestActivity.
// This should now consider the implicit show request, but keep the state from the
// explicit show request, and thus not hide the IME.
verifyInputViewStatusOnMainSync(
() -> mInputMethodService.onConfigurationChanged(config),
- EVENT_CONFIG,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is still shown after a configuration change")
- .that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_CONFIG, true /* eventExpected */, true /* shown */,
+ "IME is still shown after a configuration change");
} finally {
mInputMethodService.getResources()
.updateConfiguration(initialConfig, null /* metrics */, null /* compat */);
@@ -755,41 +614,144 @@ public class InputMethodServiceTest {
/**
* This checks that a forced show request directly followed by an explicit show request,
- * and then a hide not always request, still results in the IME being shown
- * (i.e. the explicit show request retains the forced state).
+ * and then a not always hide request behaves like a normal hide request, resulting in the
+ * IME being hidden (i.e. the explicit show request does not retain the forced state). This is
+ * due to the refactor in b/298172246, causing us to lose flag information like
+ * {@link InputMethodManager#SHOW_FORCED}.
*
- * <p>With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput
- * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like
- * HIDE_NOT_ALWAYS.
+ * <p>Previously, a forced show request directly followed by an explicit show request,
+ * and then a not always hide request, would result in the IME still being shown
+ * (i.e. the explicit show request would retain the forced state).
*/
@Test
- @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)
public void testShowSoftInputForced_testShowSoftInputExplicitly_thenHideSoftInputNotAlways() {
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_FORCED)).isTrue(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
- EVENT_SHOW,
- false /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is still shown")
- .that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, false /* eventExpected */, true /* shown */, "IME is still shown");
- verifyInputViewStatusOnMainSync(() -> assertThat(
- mActivity.hideImeWithInputMethodManager(InputMethodManager.HIDE_NOT_ALWAYS))
- .isTrue(),
- EVENT_HIDE,
- false /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is still shown after HIDE_NOT_ALWAYS")
- .that(mInputMethodService.isInputViewShown()).isTrue();
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ verifyInputViewStatusOnMainSync(() -> assertThat(mActivity
+ .hideImeWithInputMethodManager(InputMethodManager.HIDE_NOT_ALWAYS))
+ .isTrue(),
+ EVENT_HIDE, true /* eventExpected */, false /* shown */,
+ "IME is not shown after HIDE_NOT_ALWAYS");
+ } else {
+ verifyInputViewStatusOnMainSync(() -> assertThat(mActivity
+ .hideImeWithInputMethodManager(InputMethodManager.HIDE_NOT_ALWAYS))
+ .isTrue(),
+ EVENT_HIDE, false /* eventExpected */, true /* shown */,
+ "IME is still shown after HIDE_NOT_ALWAYS");
+ }
+ }
+
+ /**
+ * This checks that an explicit show request followed by an implicit only hide request
+ * behaves like a normal hide request, resulting in the IME being hidden. This is due to
+ * the refactor in b/298172246, causing us to lose flag information like
+ * {@link InputMethodManager#SHOW_IMPLICIT} and {@link InputMethodManager#HIDE_IMPLICIT_ONLY}.
+ *
+ * <p>Previously, an explicit show request followed by an implicit only hide request
+ * would result in the IME still being shown.
+ */
+ @Test
+ public void testShowSoftInputExplicitly_thenHideSoftInputImplicitOnly() {
+ setShowImeWithHardKeyboard(true /* enable */);
+
+ verifyInputViewStatusOnMainSync(
+ () -> mActivity.showImeWithInputMethodManager(0 /* flags */),
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ verifyInputViewStatusOnMainSync(
+ () -> mActivity.hideImeWithInputMethodManager(
+ InputMethodManager.HIDE_IMPLICIT_ONLY),
+ EVENT_HIDE, true /* eventExpected */, false /* shown */,
+ "IME is not shown after HIDE_IMPLICIT_ONLY");
+ } else {
+ verifyInputViewStatusOnMainSync(
+ () -> mActivity.hideImeWithInputMethodManager(
+ InputMethodManager.HIDE_IMPLICIT_ONLY),
+ EVENT_HIDE, false /* eventExpected */, true /* shown */,
+ "IME is still shown after HIDE_IMPLICIT_ONLY");
+ }
+ }
+
+ /**
+ * This checks that an implicit show request followed by an implicit only hide request
+ * results in the IME being hidden.
+ */
+ @Test
+ public void testShowSoftInputImplicitly_thenHideSoftInputImplicitOnly() {
+ setShowImeWithHardKeyboard(true /* enable */);
+
+ verifyInputViewStatusOnMainSync(
+ () -> mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT),
+ EVENT_SHOW, true /* eventExpected */, true /* shown */,
+ "IME is shown with SHOW_IMPLICIT");
+
+ verifyInputViewStatusOnMainSync(
+ () -> mActivity.hideImeWithInputMethodManager(
+ InputMethodManager.HIDE_IMPLICIT_ONLY),
+ EVENT_HIDE, true /* eventExpected */, false /* shown */,
+ "IME is not shown after HIDE_IMPLICIT_ONLY");
+ }
+
+ /**
+ * This checks that an explicit show self request followed by an implicit only hide self request
+ * behaves like a normal hide self request, resulting in the IME being hidden. This is due to
+ * the refactor in b/298172246, causing us to lose flag information like
+ * {@link InputMethodManager#SHOW_IMPLICIT} and {@link InputMethodManager#HIDE_IMPLICIT_ONLY}.
+ *
+ * <p>Previously, an explicit show self request followed by an implicit only hide self request
+ * would result in the IME still being shown.
+ */
+ @Test
+ public void testShowSelfExplicitly_thenHideSelfImplicitOnly() {
+ setShowImeWithHardKeyboard(true /* enable */);
+
+ verifyInputViewStatusOnMainSync(
+ () -> mInputMethodService.requestShowSelf(0 /* flags */),
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ verifyInputViewStatusOnMainSync(
+ () -> mInputMethodService.requestHideSelf(
+ InputMethodManager.HIDE_IMPLICIT_ONLY),
+ EVENT_HIDE, true /* eventExpected */, false /* shown */,
+ "IME is not shown after HIDE_IMPLICIT_ONLY");
+ } else {
+ verifyInputViewStatusOnMainSync(
+ () -> mInputMethodService.requestHideSelf(
+ InputMethodManager.HIDE_IMPLICIT_ONLY),
+ EVENT_HIDE, false /* eventExpected */, true /* shown */,
+ "IME is still shown after HIDE_IMPLICIT_ONLY");
+ }
+ }
+
+ /**
+ * This checks that an implicit show self request followed by an implicit only hide self request
+ * results in the IME being hidden.
+ */
+ @Test
+ public void testShowSelfImplicitly_thenHideSelfImplicitOnly() {
+ setShowImeWithHardKeyboard(true /* enable */);
+
+ verifyInputViewStatusOnMainSync(
+ () -> mInputMethodService.requestShowSelf(InputMethodManager.SHOW_IMPLICIT),
+ EVENT_SHOW, true /* eventExpected */, true /* shown */,
+ "IME is shown with SHOW_IMPLICIT");
+
+ verifyInputViewStatusOnMainSync(
+ () -> mInputMethodService.requestHideSelf(
+ InputMethodManager.HIDE_IMPLICIT_ONLY),
+ EVENT_HIDE, true /* eventExpected */, false /* shown */,
+ "IME is not shown after HIDE_IMPLICIT_ONLY");
}
/**
@@ -797,21 +759,18 @@ public class InputMethodServiceTest {
*/
@Test
public void testFullScreenMode() {
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
Log.i(TAG, "Set orientation natural");
- verifyFullscreenMode(() -> setOrientation(0),
- false /* expected */,
+ verifyFullscreenMode(() -> setOrientation(0), false /* eventExpected */,
true /* orientationPortrait */);
Log.i(TAG, "Set orientation left");
- verifyFullscreenMode(() -> setOrientation(1),
- true /* expected */,
+ verifyFullscreenMode(() -> setOrientation(1), true /* eventExpected */,
false /* orientationPortrait */);
Log.i(TAG, "Set orientation right");
- verifyFullscreenMode(() -> setOrientation(2),
- false /* expected */,
+ verifyFullscreenMode(() -> setOrientation(2), false /* eventExpected */,
false /* orientationPortrait */);
}
@@ -837,28 +796,22 @@ public class InputMethodServiceTest {
public void testShowHideImeNavigationBar_doesDrawImeNavBar() {
assumeTrue("Must have a navigation bar", hasNavigationBar());
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
- // Show IME
verifyInputViewStatusOnMainSync(
() -> {
- setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
+ setDrawsImeNavBarAndSwitcherButton(true /* enable */);
mActivity.showImeWithWindowInsetsController();
},
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
assertWithMessage("IME navigation bar is initially shown")
.that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue();
- // Try to hide IME nav bar
mInstrumentation.runOnMainSync(() -> setShowImeNavigationBar(false /* show */));
mInstrumentation.waitForIdleSync();
assertWithMessage("IME navigation bar is not shown after hide request")
.that(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse();
- // Try to show IME nav bar
mInstrumentation.runOnMainSync(() -> setShowImeNavigationBar(true /* show */));
mInstrumentation.waitForIdleSync();
assertWithMessage("IME navigation bar is shown after show request")
@@ -875,28 +828,22 @@ public class InputMethodServiceTest {
public void testShowHideImeNavigationBar_doesNotDrawImeNavBar() {
assumeTrue("Must have a navigation bar", hasNavigationBar());
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
- // Show IME
verifyInputViewStatusOnMainSync(
() -> {
- setDrawsImeNavBarAndSwitcherButton(false /* enabled */);
+ setDrawsImeNavBarAndSwitcherButton(false /* enable */);
mActivity.showImeWithWindowInsetsController();
},
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
assertWithMessage("IME navigation bar is initially not shown")
.that(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse();
- // Try to hide IME nav bar
mInstrumentation.runOnMainSync(() -> setShowImeNavigationBar(false /* show */));
mInstrumentation.waitForIdleSync();
assertWithMessage("IME navigation bar is not shown after hide request")
.that(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse();
- // Try to show IME nav bar
mInstrumentation.runOnMainSync(() -> setShowImeNavigationBar(true /* show */));
mInstrumentation.waitForIdleSync();
assertWithMessage("IME navigation bar is not shown after show request")
@@ -912,29 +859,20 @@ public class InputMethodServiceTest {
waitUntilActivityReadyForInputInjection(mActivity);
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
try (var ignored = mGestureNavSwitchHelper.withGestureNavigationMode()) {
verifyInputViewStatusOnMainSync(
() -> mActivity.showImeWithWindowInsetsController(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
- backButton.click();
- mInstrumentation.waitForIdleSync();
-
- if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // The IME visibility is only sent at the end of the animation. Therefore, we have
- // to wait until the visibility was sent to the server and the IME window hidden.
- eventually(() -> assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse());
- } else {
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
- }
+ verifyInputViewStatus(
+ () -> {
+ backButton.click();
+ mInstrumentation.waitForIdleSync();
+ },
+ EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown");
}
}
@@ -947,35 +885,25 @@ public class InputMethodServiceTest {
waitUntilActivityReadyForInputInjection(mActivity);
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
try (var ignored = mGestureNavSwitchHelper.withGestureNavigationMode()) {
verifyInputViewStatusOnMainSync(
() -> mActivity.showImeWithWindowInsetsController(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
- backButton.longClick();
- mInstrumentation.waitForIdleSync();
-
- if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // The IME visibility is only sent at the end of the animation. Therefore, we have
- // to wait until the visibility was sent to the server and the IME window hidden.
- eventually(() -> assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse());
- } else {
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
- }
+ verifyInputViewStatus(
+ () -> {
+ backButton.longClick();
+ mInstrumentation.waitForIdleSync();
+ },
+ EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown");
}
}
/**
- * Verifies that clicking on the IME switch button either shows the Input Method Switcher Menu,
- * or switches the input method.
+ * Verifies that clicking on the IME switch button switches the input method subtype.
*/
@Test
public void testImeSwitchButtonClick() throws Exception {
@@ -983,36 +911,34 @@ public class InputMethodServiceTest {
waitUntilActivityReadyForInputInjection(mActivity);
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
+
+ final var info = mImm.getCurrentInputMethodInfo();
+ assertWithMessage("InputMethodInfo is not null").that(info).isNotNull();
+ mImm.setExplicitlyEnabledInputMethodSubtypes(info.getId(), SUBTYPE_IDS);
+
+ final var initialSubtype = mImm.getCurrentInputMethodSubtype();
try (var ignored = mGestureNavSwitchHelper.withGestureNavigationMode()) {
verifyInputViewStatusOnMainSync(
() -> {
- setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
+ setDrawsImeNavBarAndSwitcherButton(true /* enable */);
mActivity.showImeWithWindowInsetsController();
},
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
-
- final var initialInfo = mImm.getCurrentInputMethodInfo();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
imeSwitcherButton.click();
mInstrumentation.waitForIdleSync();
- final var newInfo = mImm.getCurrentInputMethodInfo();
+ final var newSubtype = mImm.getCurrentInputMethodSubtype();
- assertWithMessage("Input Method Switcher Menu is shown or input method was switched")
- .that(isInputMethodPickerShown(mImm) || !Objects.equals(initialInfo, newInfo))
+ assertWithMessage("Input method subtype was switched")
+ .that(!Objects.equals(initialSubtype, newSubtype))
.isTrue();
assertWithMessage("IME is still shown after IME Switcher button was clicked")
.that(mInputMethodService.isInputViewShown()).isTrue();
-
- // Hide the IME Switcher Menu before finishing.
- mUiDevice.pressBack();
}
}
@@ -1025,18 +951,19 @@ public class InputMethodServiceTest {
waitUntilActivityReadyForInputInjection(mActivity);
- setShowImeWithHardKeyboard(true /* enabled */);
+ setShowImeWithHardKeyboard(true /* enable */);
+
+ final var info = mImm.getCurrentInputMethodInfo();
+ assertWithMessage("InputMethodInfo is not null").that(info).isNotNull();
+ mImm.setExplicitlyEnabledInputMethodSubtypes(info.getId(), SUBTYPE_IDS);
try (var ignored = mGestureNavSwitchHelper.withGestureNavigationMode()) {
verifyInputViewStatusOnMainSync(
() -> {
- setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
+ setDrawsImeNavBarAndSwitcherButton(true /* enable */);
mActivity.showImeWithWindowInsetsController();
},
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
imeSwitcherButton.longClick();
@@ -1052,58 +979,79 @@ public class InputMethodServiceTest {
}
}
- private void verifyInputViewStatus(@NonNull Runnable runnable, @Event int event,
- boolean expected, boolean inputViewStarted) {
- verifyInputViewStatusInternal(runnable, event, expected, inputViewStarted,
- false /* runOnMainSync */);
+ private void verifyInputViewStatus(@NonNull Runnable runnable, @Event int eventType,
+ boolean eventExpected, boolean shown, @NonNull String message) {
+ verifyInputViewStatusInternal(runnable, eventType, eventExpected,
+ shown /* inputViewStarted */, shown, message, false /* runOnMainSync */);
+ }
+
+ private void verifyInputViewStatusOnMainSync(@NonNull Runnable runnable, @Event int eventType,
+ boolean eventExpected, boolean shown, @NonNull String message) {
+ verifyInputViewStatusInternal(runnable, eventType, eventExpected,
+ shown /* inputViewStarted */, shown, message, true /* runOnMainSync */);
}
- private void verifyInputViewStatusOnMainSync(@NonNull Runnable runnable, @Event int event,
- boolean expected, boolean inputViewStarted) {
- verifyInputViewStatusInternal(runnable, event, expected, inputViewStarted,
- true /* runOnMainSync */);
+ private void verifyInputViewStatusOnMainSync(@NonNull Runnable runnable, @Event int eventType,
+ boolean eventExpected, boolean inputViewStarted, boolean shown,
+ @NonNull String message) {
+ verifyInputViewStatusInternal(runnable, eventType, eventExpected, inputViewStarted, shown,
+ message, true /* runOnMainSync */);
}
/**
* Verifies the status of the Input View after executing the given runnable, and waiting that
- * the event was either triggered or not, based on the given expectation.
+ * the event was either called or not.
*
- * @param runnable the runnable to trigger the event
- * @param event the event to await.
- * @param expected whether the event is expected to be triggered.
- * @param inputViewStarted the expected state of the Input View after executing the runnable.
+ * @param runnable the runnable to call the event.
+ * @param eventType the event type to wait for.
+ * @param eventExpected whether the event is expected to be called.
+ * @param inputViewStarted whether the input view is expected to be started.
+ * @param shown whether the input view is expected to be shown.
+ * @param message the message for the input view shown assertion.
* @param runOnMainSync whether to execute the runnable on the main thread.
*/
- private void verifyInputViewStatusInternal(@NonNull Runnable runnable, @Event int event,
- boolean expected, boolean inputViewStarted, boolean runOnMainSync) {
- final boolean completed;
+ private void verifyInputViewStatusInternal(@NonNull Runnable runnable, @Event int eventType,
+ boolean eventExpected, boolean inputViewStarted, boolean shown, @NonNull String message,
+ boolean runOnMainSync) {
+ final boolean eventCalled;
try {
final var latch = new CountDownLatch(1);
- mInputMethodService.setCountDownLatchForTesting(latch, event);
+ mInputMethodService.setCountDownLatchForTesting(latch, eventType);
if (runOnMainSync) {
mInstrumentation.runOnMainSync(runnable);
} else {
runnable.run();
}
mInstrumentation.waitForIdleSync();
- completed = latch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
+ eventCalled = latch.await(eventExpected ? EXPECT_TIMEOUT_MS : NOT_EXCEPT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
fail("Interrupted while waiting for latch: " + e.getMessage());
return;
} finally {
- mInputMethodService.setCountDownLatchForTesting(null /* latch */, event);
+ mInputMethodService.setCountDownLatchForTesting(null /* latch */, eventType);
}
- if (expected && !completed) {
- fail("Timed out waiting for " + eventToString(event));
- } else if (!expected && completed) {
- fail("Unexpected call " + eventToString(event));
+ if (eventExpected && !eventCalled) {
+ fail("Timed out waiting for " + eventToString(eventType));
+ } else if (!eventExpected && eventCalled) {
+ fail("Unexpected call " + eventToString(eventType));
}
- // Input is not finished.
+ // Input connection is not finished.
assertWithMessage("Input connection is still started")
.that(mInputMethodService.getCurrentInputStarted()).isTrue();
- assertWithMessage("IME visibility matches expected")
+ assertWithMessage("Input view started matches expected")
.that(mInputMethodService.getCurrentInputViewStarted()).isEqualTo(inputViewStarted);
+
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ // The IME visibility is only sent at the end of the hide animation. Therefore, we have
+ // to wait until the visibility was sent to the server and the IME window hidden.
+ eventually(() -> assertWithMessage(message).that(mInputMethodService.isInputViewShown())
+ .isEqualTo(shown));
+ } else {
+ assertWithMessage(message).that(mInputMethodService.isInputViewShown())
+ .isEqualTo(shown);
+ }
}
private void setOrientation(int orientation) {
@@ -1127,31 +1075,26 @@ public class InputMethodServiceTest {
/**
* Verifies the IME fullscreen mode state after executing the given runnable.
*
- * @param runnable the runnable to execute for setting the orientation.
- * @param expected whether the runnable is expected to trigger the signal.
+ * @param runnable the runnable to set the orientation.
+ * @param eventExpected whether the event is expected to be called.
* @param orientationPortrait whether the orientation is expected to be portrait.
*/
- private void verifyFullscreenMode(@NonNull Runnable runnable, boolean expected,
+ private void verifyFullscreenMode(@NonNull Runnable runnable, boolean eventExpected,
boolean orientationPortrait) {
- verifyInputViewStatus(runnable, EVENT_CONFIG, expected, false /* inputViewStarted */);
- if (expected) {
- // Wait for the TestActivity to be recreated.
+ verifyInputViewStatus(runnable, EVENT_CONFIG, eventExpected, false /* shown */,
+ "IME is not shown");
+ if (eventExpected) {
eventually(() -> assertWithMessage("Activity was re-created after rotation")
- .that(TestActivity.getLastCreatedInstance()).isNotEqualTo(mActivity));
- // Get the new TestActivity.
- mActivity = TestActivity.getLastCreatedInstance();
+ .that(TestActivity.getInstance()).isNotEqualTo(mActivity));
+ mActivity = TestActivity.getInstance();
assertWithMessage("Re-created activity is not null").that(mActivity).isNotNull();
// Wait for the new EditText to be served by InputMethodManager.
eventually(() -> assertWithMessage("Has an input connection to the re-created Activity")
.that(mImm.hasActiveInputConnection(mActivity.getEditText())).isTrue());
}
- verifyInputViewStatusOnMainSync(
- () -> mActivity.showImeWithWindowInsetsController(),
- EVENT_SHOW,
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ verifyInputViewStatusOnMainSync(() -> mActivity.showImeWithWindowInsetsController(),
+ EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
assertWithMessage("IME orientation matches expected")
.that(mInputMethodService.getResources().getConfiguration().orientation)
@@ -1172,21 +1115,8 @@ public class InputMethodServiceTest {
.that(mInputMethodService.isFullscreenMode()).isEqualTo(!orientationPortrait);
// Hide IME before finishing the run.
- verifyInputViewStatusOnMainSync(
- () -> mActivity.hideImeWithWindowInsetsController(),
- EVENT_HIDE,
- true /* expected */,
- false /* inputViewStarted */);
-
- if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // The IME visibility is only sent at the end of the animation. Therefore, we have to
- // wait until the visibility was sent to the server and the IME window hidden.
- eventually(() -> assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse());
- } else {
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
- }
+ verifyInputViewStatusOnMainSync(() -> mActivity.hideImeWithWindowInsetsController(),
+ EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown");
}
private void prepareIme() {
@@ -1198,6 +1128,7 @@ public class InputMethodServiceTest {
private void prepareActivity() {
mActivity = TestActivity.startSync(mInstrumentation);
+ mInstrumentation.waitForIdleSync();
Log.i(TAG, "Finish preparing activity with editor.");
}
@@ -1222,21 +1153,51 @@ public class InputMethodServiceTest {
* @param enable the value to be set.
*/
private void setShowImeWithHardKeyboard(boolean enable) {
+ if (mInputMethodService == null) {
+ // If the IME is no longer around, reset the setting unconditionally.
+ executeShellCommand(SET_SHOW_IME_WITH_HARD_KEYBOARD_CMD + " " + (enable ? "1" : "0"));
+ return;
+ }
+
final boolean currentEnabled =
mInputMethodService.getShouldShowImeWithHardKeyboardForTesting();
if (currentEnabled != enable) {
- executeShellCommand(enable
- ? ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD
- : DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD);
+ executeShellCommand(SET_SHOW_IME_WITH_HARD_KEYBOARD_CMD + " " + (enable ? "1" : "0"));
eventually(() -> assertWithMessage("showImeWithHardKeyboard updated")
.that(mInputMethodService.getShouldShowImeWithHardKeyboardForTesting())
.isEqualTo(enable));
}
}
- private static void executeShellCommand(@NonNull String cmd) {
+ /**
+ * Gets the verbose logging state in {@link android.view.inputmethod.ImeTracker}.
+ *
+ * @return {@code true} iff verbose logging is enabled.
+ */
+ private static boolean getVerboseImeTrackerLogging() {
+ return executeShellCommand(GET_VERBOSE_IME_TRACKER_LOGGING_CMD).trim().equals("1");
+ }
+
+ /**
+ * Sets verbose logging in {@link android.view.inputmethod.ImeTracker}.
+ *
+ * @param enabled whether to enable or disable verbose logging.
+ *
+ * @implNote This must use {@link ActivityManager#notifySystemPropertiesChanged()} to listen
+ * for changes to the system property for the verbose ImeTracker logging.
+ */
+ private void setVerboseImeTrackerLogging(boolean enabled) {
+ final var context = mInstrumentation.getContext();
+ final var am = context.getSystemService(ActivityManager.class);
+
+ executeShellCommand(SET_VERBOSE_IME_TRACKER_LOGGING_CMD + " " + (enabled ? "1" : "0"));
+ am.notifySystemPropertiesChanged();
+ }
+
+ @NonNull
+ private static String executeShellCommand(@NonNull String cmd) {
Log.i(TAG, "Run command: " + cmd);
- SystemUtil.runShellCommandOrThrow(cmd);
+ return SystemUtil.runShellCommandOrThrow(cmd);
}
/**
@@ -1249,8 +1210,7 @@ public class InputMethodServiceTest {
@NonNull
private UiObject2 getUiObject(@NonNull BySelector bySelector) {
- final var uiObject = mUiDevice.wait(Until.findObject(bySelector),
- TimeUnit.SECONDS.toMillis(TIMEOUT_IN_SECONDS));
+ final var uiObject = mUiDevice.wait(Until.findObject(bySelector), TIMEOUT_MS);
assertWithMessage("UiObject with " + bySelector + " was found").that(uiObject).isNotNull();
return uiObject;
}
@@ -1273,10 +1233,10 @@ public class InputMethodServiceTest {
*
* <p>Note, neither of these are normally drawn when in three button navigation mode.
*
- * @param enabled whether the IME nav bar and IME Switcher button are drawn.
+ * @param enable whether the IME nav bar and IME Switcher button are drawn.
*/
- private void setDrawsImeNavBarAndSwitcherButton(boolean enabled) {
- final int flags = enabled ? IME_DRAWS_IME_NAV_BAR | SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0;
+ private void setDrawsImeNavBarAndSwitcherButton(boolean enable) {
+ final int flags = enable ? IME_DRAWS_IME_NAV_BAR | SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0;
mInputMethodService.getInputMethodInternal().onNavButtonFlagsChanged(flags);
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index 3af5db9841ea..6af4064b1288 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -66,6 +66,7 @@ import com.android.internal.inputmethod.IInputMethodSession;
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.inputmethod.IRemoteInputConnection;
import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.protolog.IProtoLogConfigurationService;
import com.android.internal.view.IInputMethodManager;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
@@ -124,6 +125,7 @@ public class InputMethodManagerServiceTestBase {
@Mock protected IBinder mMockInputMethodBinder;
@Mock protected IInputManager mMockIInputManager;
@Mock protected ImeTargetVisibilityPolicy mMockImeTargetVisibilityPolicy;
+ @Mock protected IProtoLogConfigurationService.Stub mMockProtoLogConfigurationService;
protected Context mContext;
protected MockitoSession mMockingSession;
@@ -186,6 +188,9 @@ public class InputMethodManagerServiceTestBase {
.when(() -> ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
doReturn(mMockIPlatformCompat)
.when(() -> ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ doReturn(mMockProtoLogConfigurationService)
+ .when(() -> ServiceManager.getServiceOrThrow(
+ Context.PROTOLOG_CONFIGURATION_SERVICE));
// Stubbing out context related methods to avoid the system holding strong references to
// InputMethodManagerService.
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/res/xml/method.xml b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/res/xml/method.xml
index 872b0688814a..3dd4a97f464f 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/res/xml/method.xml
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/res/xml/method.xml
@@ -17,7 +17,14 @@
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
<subtype
- android:label="FakeIme"
+ android:label="SimpleIme"
android:imeSubtypeLocale="en_US"
- android:imeSubtypeMode="keyboard"/>
+ android:imeSubtypeMode="keyboard"
+ android:subtypeId="1" />
+
+ <subtype
+ android:label="SimpleIme French"
+ android:imeSubtypeLocale="fr_FR"
+ android:imeSubtypeMode="keyboard"
+ android:subtypeId="2" />
</input-method> \ No newline at end of file
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/KeyCodeConstants.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/KeyCodeConstants.java
index 990fa24aad22..428ce1f6e1f6 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/KeyCodeConstants.java
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/KeyCodeConstants.java
@@ -18,51 +18,58 @@ package com.android.apps.inputmethod.simpleime;
import android.view.KeyEvent;
-import java.util.HashMap;
+import androidx.annotation.NonNull;
/** Holder of key codes and their name. */
-public final class KeyCodeConstants {
- private KeyCodeConstants() {}
+final class KeyCodeConstants {
- static final HashMap<String, Integer> KEY_NAME_TO_CODE_MAP = new HashMap<>();
+ private KeyCodeConstants() {
+ }
- static {
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_A", KeyEvent.KEYCODE_A);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_B", KeyEvent.KEYCODE_B);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_C", KeyEvent.KEYCODE_C);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_D", KeyEvent.KEYCODE_D);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_E", KeyEvent.KEYCODE_E);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_F", KeyEvent.KEYCODE_F);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_G", KeyEvent.KEYCODE_G);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_H", KeyEvent.KEYCODE_H);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_I", KeyEvent.KEYCODE_I);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_J", KeyEvent.KEYCODE_J);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_K", KeyEvent.KEYCODE_K);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_L", KeyEvent.KEYCODE_L);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_M", KeyEvent.KEYCODE_M);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_N", KeyEvent.KEYCODE_N);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_O", KeyEvent.KEYCODE_O);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_P", KeyEvent.KEYCODE_P);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_Q", KeyEvent.KEYCODE_Q);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_R", KeyEvent.KEYCODE_R);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_S", KeyEvent.KEYCODE_S);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_T", KeyEvent.KEYCODE_T);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_U", KeyEvent.KEYCODE_U);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_V", KeyEvent.KEYCODE_V);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_W", KeyEvent.KEYCODE_W);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_X", KeyEvent.KEYCODE_X);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_Y", KeyEvent.KEYCODE_Y);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_Z", KeyEvent.KEYCODE_Z);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_SHIFT", KeyEvent.KEYCODE_SHIFT_LEFT);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_DEL", KeyEvent.KEYCODE_DEL);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_SPACE", KeyEvent.KEYCODE_SPACE);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_ENTER", KeyEvent.KEYCODE_ENTER);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_COMMA", KeyEvent.KEYCODE_COMMA);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_PERIOD", KeyEvent.KEYCODE_PERIOD);
- KEY_NAME_TO_CODE_MAP.put("KEYCODE_TAB", KeyEvent.KEYCODE_TAB);
+ /**
+ * Returns the keyCode value corresponding to the given keyCode name.
+ *
+ * @param keyCodeName the keyCode name.
+ */
+ static int getKeyCode(@NonNull String keyCodeName) {
+ return switch (keyCodeName) {
+ case "KEYCODE_A" -> KeyEvent.KEYCODE_A;
+ case "KEYCODE_B" -> KeyEvent.KEYCODE_B;
+ case "KEYCODE_C" -> KeyEvent.KEYCODE_C;
+ case "KEYCODE_D" -> KeyEvent.KEYCODE_D;
+ case "KEYCODE_E" -> KeyEvent.KEYCODE_E;
+ case "KEYCODE_F" -> KeyEvent.KEYCODE_F;
+ case "KEYCODE_G" -> KeyEvent.KEYCODE_G;
+ case "KEYCODE_H" -> KeyEvent.KEYCODE_H;
+ case "KEYCODE_I" -> KeyEvent.KEYCODE_I;
+ case "KEYCODE_J" -> KeyEvent.KEYCODE_J;
+ case "KEYCODE_K" -> KeyEvent.KEYCODE_K;
+ case "KEYCODE_L" -> KeyEvent.KEYCODE_L;
+ case "KEYCODE_M" -> KeyEvent.KEYCODE_M;
+ case "KEYCODE_N" -> KeyEvent.KEYCODE_N;
+ case "KEYCODE_O" -> KeyEvent.KEYCODE_O;
+ case "KEYCODE_P" -> KeyEvent.KEYCODE_P;
+ case "KEYCODE_Q" -> KeyEvent.KEYCODE_Q;
+ case "KEYCODE_R" -> KeyEvent.KEYCODE_R;
+ case "KEYCODE_S" -> KeyEvent.KEYCODE_S;
+ case "KEYCODE_T" -> KeyEvent.KEYCODE_T;
+ case "KEYCODE_U" -> KeyEvent.KEYCODE_U;
+ case "KEYCODE_V" -> KeyEvent.KEYCODE_V;
+ case "KEYCODE_W" -> KeyEvent.KEYCODE_W;
+ case "KEYCODE_X" -> KeyEvent.KEYCODE_X;
+ case "KEYCODE_Y" -> KeyEvent.KEYCODE_Y;
+ case "KEYCODE_Z" -> KeyEvent.KEYCODE_Z;
+ case "KEYCODE_SHIFT" -> KeyEvent.KEYCODE_SHIFT_LEFT;
+ case "KEYCODE_DEL" -> KeyEvent.KEYCODE_DEL;
+ case "KEYCODE_SPACE" -> KeyEvent.KEYCODE_SPACE;
+ case "KEYCODE_ENTER" -> KeyEvent.KEYCODE_ENTER;
+ case "KEYCODE_COMMA" -> KeyEvent.KEYCODE_COMMA;
+ case "KEYCODE_PERIOD" -> KeyEvent.KEYCODE_PERIOD;
+ default -> KeyEvent.KEYCODE_UNKNOWN;
+ };
}
- public static boolean isAlphaKeyCode(int keyCode) {
+ static boolean isAlphaKeyCode(int keyCode) {
return keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z;
}
}
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleInputMethodService.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleInputMethodService.java
index 61d1bb931a96..de9b5289be9d 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleInputMethodService.java
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleInputMethodService.java
@@ -20,45 +20,41 @@ import android.inputmethodservice.InputMethodService;
import android.os.SystemClock;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import com.android.apps.inputmethod.simpleime.ims.InputMethodServiceWrapper;
-/** The {@link InputMethodService} implementation for SimpleTestIme app. */
+/** A simple implementation of an {@link InputMethodService}. */
public final class SimpleInputMethodService extends InputMethodServiceWrapper {
private static final String TAG = "SimpleIMS";
- private FrameLayout mInputView;
-
@Override
public View onCreateInputView() {
Log.i(TAG, "onCreateInputView()");
- mInputView = (FrameLayout) LayoutInflater.from(this).inflate(R.layout.input_view, null);
- return mInputView;
- }
-
- @Override
- public void onStartInputView(EditorInfo info, boolean restarting) {
- super.onStartInputView(info, restarting);
- mInputView.removeAllViews();
- final var keyboard = new SimpleKeyboard(this, R.layout.qwerty_10_9_9);
- mInputView.addView(keyboard.inflateKeyboardView(LayoutInflater.from(this), mInputView));
+ final var simpleKeyboard = new SimpleKeyboardView(this);
+ simpleKeyboard.setKeyPressListener(this::onKeyPress);
+ return simpleKeyboard;
}
- void handleKeyPress(@NonNull String keyCodeName, int keyboardState) {
- final Integer keyCode = KeyCodeConstants.KEY_NAME_TO_CODE_MAP.get(keyCodeName);
- Log.v(TAG, "keyCode: " + keyCode);
- if (keyCode != null) {
- final var downTime = SystemClock.uptimeMillis();
- getCurrentInputConnection().sendKeyEvent(new KeyEvent(downTime, downTime,
- KeyEvent.ACTION_DOWN, keyCode, 0 /* repeat */,
- KeyCodeConstants.isAlphaKeyCode(keyCode) ? keyboardState : 0) /* metaState */);
+ /**
+ * Called when a key is pressed.
+ *
+ * @param keyCodeName the keycode of the key, as a string.
+ * @param metaState the flags indicating which meta keys are currently pressed.
+ */
+ private void onKeyPress(@NonNull String keyCodeName, int metaState) {
+ final int keyCode = KeyCodeConstants.getKeyCode(keyCodeName);
+ Log.v(TAG, "onKeyPress: " + keyCode);
+ if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+ final var ic = getCurrentInputConnection();
+ if (ic != null) {
+ final var downTime = SystemClock.uptimeMillis();
+ ic.sendKeyEvent(new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode,
+ 0 /* repeat */, KeyCodeConstants.isAlphaKeyCode(keyCode) ? metaState : 0));
+ }
}
}
}
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleKeyboard.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleKeyboard.java
deleted file mode 100644
index 62d90c8d56b5..000000000000
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleKeyboard.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2022 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.apps.inputmethod.simpleime;
-
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/** Controls the visible virtual keyboard view. */
-final class SimpleKeyboard {
-
- private static final String TAG = "SimpleKeyboard";
-
- private static final int[] SOFT_KEY_IDS = new int[]{
- R.id.key_pos_0_0,
- R.id.key_pos_0_1,
- R.id.key_pos_0_2,
- R.id.key_pos_0_3,
- R.id.key_pos_0_4,
- R.id.key_pos_0_5,
- R.id.key_pos_0_6,
- R.id.key_pos_0_7,
- R.id.key_pos_0_8,
- R.id.key_pos_0_9,
- R.id.key_pos_1_0,
- R.id.key_pos_1_1,
- R.id.key_pos_1_2,
- R.id.key_pos_1_3,
- R.id.key_pos_1_4,
- R.id.key_pos_1_5,
- R.id.key_pos_1_6,
- R.id.key_pos_1_7,
- R.id.key_pos_1_8,
- R.id.key_pos_2_0,
- R.id.key_pos_2_1,
- R.id.key_pos_2_2,
- R.id.key_pos_2_3,
- R.id.key_pos_2_4,
- R.id.key_pos_2_5,
- R.id.key_pos_2_6,
- R.id.key_pos_shift,
- R.id.key_pos_del,
- R.id.key_pos_symbol,
- R.id.key_pos_comma,
- R.id.key_pos_space,
- R.id.key_pos_period,
- R.id.key_pos_enter,
- };
-
- @NonNull
- private final SimpleInputMethodService mSimpleInputMethodService;
- private final int mViewResId;
- private final SparseArray<TextView> mSoftKeyViews = new SparseArray<>();
- private View mKeyboardView;
- private int mKeyboardState;
-
- SimpleKeyboard(@NonNull SimpleInputMethodService simpleInputMethodService, int viewResId) {
- mSimpleInputMethodService = simpleInputMethodService;
- mViewResId = viewResId;
- mKeyboardState = 0;
- }
-
- @NonNull
- View inflateKeyboardView(@NonNull LayoutInflater inflater, @NonNull ViewGroup inputView) {
- mKeyboardView = inflater.inflate(mViewResId, inputView, false);
- mapSoftKeys();
- return mKeyboardView;
- }
-
- private void mapSoftKeys() {
- for (int id : SOFT_KEY_IDS) {
- final TextView softKeyView = mKeyboardView.requireViewById(id);
- mSoftKeyViews.put(id, softKeyView);
- final var keyCodeName = softKeyView.getTag() != null
- ? softKeyView.getTag().toString() : null;
- softKeyView.setOnClickListener(v -> handleKeyPress(keyCodeName));
- }
- }
-
- private void handleKeyPress(@Nullable String keyCodeName) {
- Log.i(TAG, "handle(): " + keyCodeName);
- if (TextUtils.isEmpty(keyCodeName)) {
- return;
- }
- if ("KEYCODE_SHIFT".equals(keyCodeName)) {
- handleShift();
- return;
- }
-
- mSimpleInputMethodService.handleKeyPress(keyCodeName, mKeyboardState);
- }
-
- private void handleShift() {
- mKeyboardState = toggleShiftState(mKeyboardState);
- Log.v(TAG, "currentKeyboardState: " + mKeyboardState);
- final boolean isShiftOn = isShiftOn(mKeyboardState);
- for (int i = 0; i < mSoftKeyViews.size(); i++) {
- TextView softKeyView = mSoftKeyViews.valueAt(i);
- softKeyView.setAllCaps(isShiftOn);
- }
- }
-
- private static boolean isShiftOn(int state) {
- return (state & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
- }
-
- private static int toggleShiftState(int state) {
- return state ^ KeyEvent.META_SHIFT_ON;
- }
-}
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleKeyboardView.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleKeyboardView.java
new file mode 100644
index 000000000000..1840cdea4c20
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/SimpleKeyboardView.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2022 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.apps.inputmethod.simpleime;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import androidx.annotation.AttrRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/** A simple implementation of a software keyboard view. */
+final class SimpleKeyboardView extends FrameLayout {
+
+ private static final String TAG = "SimpleKeyboard";
+
+ private static final int[] SOFT_KEY_IDS = new int[]{
+ R.id.key_pos_0_0,
+ R.id.key_pos_0_1,
+ R.id.key_pos_0_2,
+ R.id.key_pos_0_3,
+ R.id.key_pos_0_4,
+ R.id.key_pos_0_5,
+ R.id.key_pos_0_6,
+ R.id.key_pos_0_7,
+ R.id.key_pos_0_8,
+ R.id.key_pos_0_9,
+ R.id.key_pos_1_0,
+ R.id.key_pos_1_1,
+ R.id.key_pos_1_2,
+ R.id.key_pos_1_3,
+ R.id.key_pos_1_4,
+ R.id.key_pos_1_5,
+ R.id.key_pos_1_6,
+ R.id.key_pos_1_7,
+ R.id.key_pos_1_8,
+ R.id.key_pos_2_0,
+ R.id.key_pos_2_1,
+ R.id.key_pos_2_2,
+ R.id.key_pos_2_3,
+ R.id.key_pos_2_4,
+ R.id.key_pos_2_5,
+ R.id.key_pos_2_6,
+ R.id.key_pos_shift,
+ R.id.key_pos_del,
+ R.id.key_pos_symbol,
+ R.id.key_pos_comma,
+ R.id.key_pos_space,
+ R.id.key_pos_period,
+ R.id.key_pos_enter,
+ };
+
+ private final SparseArray<TextView> mSoftKeyViews = new SparseArray<>();
+
+ @FunctionalInterface
+ interface KeyPressListener {
+
+ /**
+ * Called when a key is pressed.
+ *
+ * @param keyCodeName the keycode of the key, as a string.
+ * @param metaState the flags indicating which meta keys are currently pressed.
+ */
+ void onKeyPress(@NonNull String keyCodeName, int metaState);
+ }
+
+ /** A listener to react to key presses. */
+ @Nullable
+ private KeyPressListener mKeyPressListener;
+
+ /** The flags indicating which meta keys are currently pressed. */
+ private int mMetaState;
+
+ SimpleKeyboardView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ SimpleKeyboardView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0 /* defStyleAttr */);
+ }
+
+ SimpleKeyboardView(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
+ super(context, attrs, defStyleAttr, 0 /* defStyleRes */);
+ LayoutInflater.from(context).inflate(R.layout.qwerty_10_9_9, this, true);
+ mapSoftKeys();
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ // Handle edge to edge for navigationBars insets (system nav bar)
+ // and captionBars insets (IME navigation bar).
+ final int insetBottom = insets.getInsets(WindowInsets.Type.systemBars()).bottom;
+ setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), insetBottom);
+ return insets.inset(0, 0, 0, insetBottom);
+ }
+
+ /**
+ * Sets the key press listener.
+ *
+ * @param listener the listener to set.
+ */
+ void setKeyPressListener(@NonNull KeyPressListener listener) {
+ mKeyPressListener = listener;
+ }
+
+ /** Maps the soft key ids to their corresponding views, and sets their on click listener. */
+ private void mapSoftKeys() {
+ for (final int id : SOFT_KEY_IDS) {
+ final TextView softKeyView = requireViewById(id);
+ mSoftKeyViews.put(id, softKeyView);
+ final var keyCodeName = softKeyView.getTag() != null
+ ? softKeyView.getTag().toString() : null;
+ softKeyView.setOnClickListener(v -> onKeyPress(keyCodeName));
+ }
+ }
+
+ /**
+ * Called when a key is pressed.
+ *
+ * @param keyCodeName the keycode of the key, as a string.
+ */
+ private void onKeyPress(@Nullable String keyCodeName) {
+ Log.i(TAG, "onKeyPress: " + keyCodeName);
+ if (TextUtils.isEmpty(keyCodeName)) {
+ return;
+ }
+ if ("KEYCODE_SHIFT".equals(keyCodeName)) {
+ onShiftPress();
+ return;
+ }
+
+ if (mKeyPressListener != null) {
+ mKeyPressListener.onKeyPress(keyCodeName, mMetaState);
+ }
+ }
+
+ /**
+ * Called when the shift key is pressed. This will toggle the capitalization of all the keys.
+ */
+ private void onShiftPress() {
+ mMetaState = toggleShiftState(mMetaState);
+ Log.v(TAG, "onShiftPress, new metaState: " + mMetaState);
+ final boolean isShiftOn = isShiftOn(mMetaState);
+ for (int i = 0; i < mSoftKeyViews.size(); i++) {
+ final TextView softKeyView = mSoftKeyViews.valueAt(i);
+ softKeyView.setAllCaps(isShiftOn);
+ }
+ }
+
+ /**
+ * Checks whether the shift meta key is pressed.
+ *
+ * @param state the flags indicating which meta keys are currently pressed.
+ */
+ private static boolean isShiftOn(int state) {
+ return (state & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
+ }
+
+ /**
+ * Toggles the value of the shift meta key being pressed.
+ *
+ * @param state the flags indicating which meta keys are currently pressed.
+ * @return a new flag state, with the shift meta key value flipped.
+ */
+ private static int toggleShiftState(int state) {
+ return state ^ KeyEvent.META_SHIFT_ON;
+ }
+}
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java
index 3a7abbb167ec..d4d4dcaa4f48 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java
@@ -27,6 +27,7 @@ import androidx.annotation.Nullable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.util.concurrent.CountDownLatch;
/** Wrapper of {@link InputMethodService} to expose interfaces for testing purpose. */
@@ -35,8 +36,8 @@ public class InputMethodServiceWrapper extends InputMethodService {
private static final String TAG = "InputMethodServiceWrapper";
/** Last created instance of this wrapper. */
- @Nullable
- private static InputMethodServiceWrapper sInstance;
+ @NonNull
+ private static WeakReference<InputMethodServiceWrapper> sInstance = new WeakReference<>(null);
/** IME show event ({@link #onStartInputView}). */
public static final int EVENT_SHOW = 0;
@@ -68,32 +69,11 @@ public class InputMethodServiceWrapper extends InputMethodService {
@Nullable
private CountDownLatch mCountDownLatch;
- /** Gets the last created instance of this wrapper, if available. */
- @Nullable
- public static InputMethodServiceWrapper getInstance() {
- return sInstance;
- }
-
- public boolean getCurrentInputViewStarted() {
- return mInputViewStarted;
- }
-
- /**
- * Sets the latch used to wait for the IME event.
- *
- * @param latch the latch to wait on.
- * @param latchEvent the event to set the latch on.
- */
- public void setCountDownLatchForTesting(@Nullable CountDownLatch latch, @Event int latchEvent) {
- mCountDownLatch = latch;
- mLatchEvent = latchEvent;
- }
-
@Override
public void onCreate() {
Log.i(TAG, "onCreate()");
super.onCreate();
- sInstance = this;
+ sInstance = new WeakReference<>(this);
}
@Override
@@ -103,6 +83,12 @@ public class InputMethodServiceWrapper extends InputMethodService {
}
@Override
+ public void onFinishInput() {
+ Log.i(TAG, "onFinishInput()");
+ super.onFinishInput();
+ }
+
+ @Override
public void onStartInputView(EditorInfo info, boolean restarting) {
Log.i(TAG, "onStartInputView() editor=" + dumpEditorInfo(info)
+ ", restarting=" + restarting);
@@ -114,12 +100,6 @@ public class InputMethodServiceWrapper extends InputMethodService {
}
@Override
- public void onFinishInput() {
- Log.i(TAG, "onFinishInput()");
- super.onFinishInput();
- }
-
- @Override
public void onFinishInputView(boolean finishingInput) {
Log.i(TAG, "onFinishInputView()");
super.onFinishInputView(finishingInput);
@@ -131,12 +111,6 @@ public class InputMethodServiceWrapper extends InputMethodService {
}
@Override
- public void requestHideSelf(int flags) {
- Log.i(TAG, "requestHideSelf() " + flags);
- super.requestHideSelf(flags);
- }
-
- @Override
public void onConfigurationChanged(Configuration newConfig) {
Log.i(TAG, "onConfigurationChanged() " + newConfig);
super.onConfigurationChanged(newConfig);
@@ -146,14 +120,35 @@ public class InputMethodServiceWrapper extends InputMethodService {
}
}
+ public boolean getCurrentInputViewStarted() {
+ return mInputViewStarted;
+ }
+
+ /**
+ * Sets the latch used to wait for the IME event.
+ *
+ * @param latch the latch to wait on.
+ * @param latchEvent the event to set the latch on.
+ */
+ public void setCountDownLatchForTesting(@Nullable CountDownLatch latch, @Event int latchEvent) {
+ mCountDownLatch = latch;
+ mLatchEvent = latchEvent;
+ }
+
+ /** Gets the last created instance of this wrapper, if available. */
+ @Nullable
+ public static InputMethodServiceWrapper getInstance() {
+ return sInstance.get();
+ }
+
/**
* Gets the string representation of the IME event that is being waited on.
*
- * @param event the IME event.
+ * @param eventType the IME event type.
*/
@NonNull
- public static String eventToString(@Event int event) {
- return switch (event) {
+ public static String eventToString(@Event int eventType) {
+ return switch (eventType) {
case EVENT_SHOW -> "onStartInputView";
case EVENT_HIDE -> "onFinishInputView";
case EVENT_CONFIG -> "onConfigurationChanged";
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java
index eadbac3ca74b..ad90b32848b0 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java
@@ -45,30 +45,13 @@ import java.lang.ref.WeakReference;
public final class TestActivity extends Activity {
private static final String TAG = "TestActivity";
- private static WeakReference<TestActivity> sLastCreatedInstance = new WeakReference<>(null);
- /**
- * Start a new test activity with an editor and wait for it to begin running before returning.
- *
- * @param instrumentation application instrumentation
- * @return the newly started activity
- */
+ /** Last created instance of this activity. */
@NonNull
- public static TestActivity startSync(@NonNull Instrumentation instrumentation) {
- final var intent = new Intent()
- .setAction(Intent.ACTION_MAIN)
- .setClass(instrumentation.getTargetContext(), TestActivity.class)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- return (TestActivity) instrumentation.startActivitySync(intent);
- }
+ private static WeakReference<TestActivity> sInstance = new WeakReference<>(null);
private EditText mEditText;
- public EditText getEditText() {
- return mEditText;
- }
-
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -80,13 +63,11 @@ public final class TestActivity extends Activity {
rootView.setFitsSystemWindows(true);
setContentView(rootView);
mEditText.requestFocus();
- sLastCreatedInstance = new WeakReference<>(this);
+ sInstance = new WeakReference<>(this);
}
- /** Get the last created TestActivity instance, if available. */
- @Nullable
- public static TestActivity getLastCreatedInstance() {
- return sLastCreatedInstance.get();
+ public EditText getEditText() {
+ return mEditText;
}
/** Shows soft keyboard via InputMethodManager. */
@@ -118,4 +99,26 @@ public final class TestActivity extends Activity {
controller.hide(WindowInsets.Type.ime());
Log.i(TAG, "hideIme() via WindowInsetsController");
}
+
+ /** Gets the last created instance of this activity, if available. */
+ @Nullable
+ public static TestActivity getInstance() {
+ return sInstance.get();
+ }
+
+ /**
+ * Start a new test activity with an editor and wait for it to begin running before returning.
+ *
+ * @param instrumentation application instrumentation.
+ * @return the newly started activity.
+ */
+ @NonNull
+ public static TestActivity startSync(@NonNull Instrumentation instrumentation) {
+ final var intent = new Intent()
+ .setAction(Intent.ACTION_MAIN)
+ .setClass(instrumentation.getTargetContext(), TestActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ return (TestActivity) instrumentation.startActivitySync(intent);
+ }
}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index f5c0de034483..e1c65d27459e 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -65,10 +65,13 @@ import android.content.pm.SigningDetails;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArraySet;
import androidx.annotation.Nullable;
@@ -150,6 +153,9 @@ public class PackageParserTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private File mTmpDir;
private static final File FRAMEWORK = new File("/system/framework/framework-res.apk");
private static final String TEST_APP1_APK = "PackageParserTestApp1.apk";
@@ -846,7 +852,42 @@ public class PackageParserTest {
@Test
@RequiresFlagsEnabled(android.content.res.Flags.FLAG_MANIFEST_FLAGGING)
- public void testParseWithFeatureFlagAttributes() throws Exception {
+ @DisableFlags(android.content.res.Flags.FLAG_USE_NEW_ACONFIG_STORAGE)
+ public void testParseWithFeatureFlagAttributes_oldStorage() throws Exception {
+ final File testFile = extractFile(TEST_APP8_APK);
+ try (PackageParser2 parser = new TestPackageParser2()) {
+ Map<String, Boolean> flagValues = new HashMap<>();
+ flagValues.put("my.flag1", true);
+ flagValues.put("my.flag2", false);
+ flagValues.put("my.flag3", false);
+ flagValues.put("my.flag4", true);
+ ParsingPackageUtils.getAconfigFlags().addFlagValuesForTesting(flagValues);
+
+ // The manifest has:
+ // <permission android:name="PERM1" android:featureFlag="my.flag1 " />
+ // <permission android:name="PERM2" android:featureFlag=" !my.flag2" />
+ // <permission android:name="PERM3" android:featureFlag="my.flag3" />
+ // <permission android:name="PERM4" android:featureFlag="!my.flag4" />
+ // <permission android:name="PERM5" android:featureFlag="unknown.flag" />
+ // Therefore with the above flag values, only PERM1 and PERM2 should be present.
+
+ final ParsedPackage pkg = parser.parsePackage(testFile, 0, false);
+ List<String> permissionNames =
+ pkg.getPermissions().stream().map(ParsedComponent::getName).toList();
+ assertThat(permissionNames).contains(PACKAGE_NAME + ".PERM1");
+ assertThat(permissionNames).contains(PACKAGE_NAME + ".PERM2");
+ assertThat(permissionNames).doesNotContain(PACKAGE_NAME + ".PERM3");
+ assertThat(permissionNames).doesNotContain(PACKAGE_NAME + ".PERM4");
+ assertThat(permissionNames).doesNotContain(PACKAGE_NAME + ".PERM5");
+ } finally {
+ testFile.delete();
+ }
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.content.res.Flags.FLAG_MANIFEST_FLAGGING)
+ @EnableFlags(android.content.res.Flags.FLAG_USE_NEW_ACONFIG_STORAGE)
+ public void testParseWithFeatureFlagAttributes_newStorage() throws Exception {
final File testFile = extractFile(TEST_APP8_APK);
try (PackageParser2 parser = new TestPackageParser2()) {
Map<String, Boolean> flagValues = new HashMap<>();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
index 00296745a81f..38586155993e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
@@ -23,10 +23,17 @@ import static android.view.Surface.ROTATION_90;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
import android.graphics.Point;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
+import android.view.Surface;
import android.view.SurfaceControl;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -37,6 +44,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
/**
@@ -154,6 +162,65 @@ public class DisplayDeviceTest {
assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(LANDSCAPE_SIZE);
}
+ @Test
+ public void testSetDisplaySize_landscapeInstallRotation() {
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+ mMockDisplayAdapter);
+ mDisplayDeviceInfo.installOrientation = Surface.ROTATION_0;
+ mDisplayDeviceInfo.width = 100;
+ mDisplayDeviceInfo.height = 200;
+ displayDevice.configureDisplaySizeLocked(mMockTransaction);
+ verify(mMockTransaction).setDisplaySize(isNull(), eq(100), eq(200));
+
+ Mockito.clearInvocations(mMockTransaction);
+
+ mDisplayDeviceInfo.installOrientation = Surface.ROTATION_180;
+ mDisplayDeviceInfo.width = 300;
+ mDisplayDeviceInfo.height = 400;
+ displayDevice.configureDisplaySizeLocked(mMockTransaction);
+ verify(mMockTransaction).setDisplaySize(isNull(), eq(300), eq(400));
+ }
+
+ @Test
+ public void testSetDisplaySize_portraitInstallRotation() {
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+ mMockDisplayAdapter);
+ mDisplayDeviceInfo.installOrientation = Surface.ROTATION_90;
+ mDisplayDeviceInfo.width = 100;
+ mDisplayDeviceInfo.height = 200;
+ displayDevice.configureDisplaySizeLocked(mMockTransaction);
+ verify(mMockTransaction).setDisplaySize(isNull(), eq(200), eq(100));
+
+ Mockito.clearInvocations(mMockTransaction);
+
+ mDisplayDeviceInfo.installOrientation = Surface.ROTATION_270;
+ mDisplayDeviceInfo.width = 300;
+ mDisplayDeviceInfo.height = 400;
+ displayDevice.configureDisplaySizeLocked(mMockTransaction);
+ verify(mMockTransaction).setDisplaySize(isNull(), eq(400), eq(300));
+ }
+
+ @Test
+ public void testSetDisplaySize_invokedOnlyAfterResize() {
+ DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo,
+ mMockDisplayAdapter);
+ mDisplayDeviceInfo.installOrientation = Surface.ROTATION_90;
+ mDisplayDeviceInfo.width = 100;
+ mDisplayDeviceInfo.height = 200;
+ displayDevice.configureDisplaySizeLocked(mMockTransaction);
+ verify(mMockTransaction).setDisplaySize(isNull(), eq(200), eq(100));
+
+ Mockito.clearInvocations(mMockTransaction);
+
+ displayDevice.configureDisplaySizeLocked(mMockTransaction);
+ verify(mMockTransaction, never()).setDisplaySize(isNull(), anyInt(), anyInt());
+
+ mDisplayDeviceInfo.width = 300;
+ mDisplayDeviceInfo.height = 400;
+ displayDevice.configureDisplaySizeLocked(mMockTransaction);
+ verify(mMockTransaction).setDisplaySize(isNull(), eq(400), eq(300));
+ }
+
private static class FakeDisplayDevice extends DisplayDevice {
private final DisplayDeviceInfo mDisplayDeviceInfo;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
index b9cea0c72306..f8b4113a3c04 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -550,10 +550,10 @@ public class LocalDisplayAdapterTest {
assertDisplayDpi(
mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, 100, 100,
- 100);
+ 136);
assertDisplayDpi(
mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_B, 100, 100,
- 100);
+ 136);
}
private static class DisplayModeWrapper {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 7d3cd8a8a9ae..38de7ce013c2 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -34,6 +34,7 @@ import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_REM
import static com.android.server.display.DisplayDeviceInfo.DIFF_EVERYTHING;
import static com.android.server.display.DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED;
+import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CONNECTED;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DISCONNECTED;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED;
@@ -1180,13 +1181,21 @@ public class LogicalDisplayMapperTest {
assertEquals(LOGICAL_DISPLAY_EVENT_STATE_CHANGED,
mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo));
+ // Change the display committed state
+ when(mFlagsMock.isCommittedStateSeparateEventEnabled()).thenReturn(true);
+ newDisplayInfo = new DisplayInfo();
+ newDisplayInfo.committedState = STATE_OFF;
+ assertEquals(LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED,
+ mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo));
// Change multiple properties
newDisplayInfo = new DisplayInfo();
newDisplayInfo.refreshRateOverride = 30;
newDisplayInfo.state = STATE_OFF;
+ newDisplayInfo.committedState = STATE_OFF;
assertEquals(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED
- | LOGICAL_DISPLAY_EVENT_STATE_CHANGED,
+ | LOGICAL_DISPLAY_EVENT_STATE_CHANGED
+ | LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED,
mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo));
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
index 1a0ab252f128..37f8aba1fb6c 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
@@ -159,7 +159,8 @@ public class LogicalDisplayTest {
mDisplayDeviceInfo.type = Display.TYPE_INTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
- /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true,
+ /*isSyncedResolutionSwitchEnabled=*/ true);
// In case of Anisotropy of pixels, then the content should be rescaled so it would adjust
// to using the whole screen. This is because display will rescale it back to fill the
@@ -188,7 +189,8 @@ public class LogicalDisplayTest {
mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
- /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true,
+ /*isSyncedResolutionSwitchEnabled=*/ true);
// In case of Anisotropy of pixels, then the content should be rescaled so it would adjust
// to using the whole screen. This is because display will rescale it back to fill the
@@ -217,7 +219,8 @@ public class LogicalDisplayTest {
mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
- /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true,
+ /*isSyncedResolutionSwitchEnabled=*/ true);
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.logicalWidth = DISPLAY_WIDTH;
@@ -275,7 +278,8 @@ public class LogicalDisplayTest {
mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
- /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true,
+ /*isSyncedResolutionSwitchEnabled=*/ true);
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.logicalWidth = DISPLAY_WIDTH;
@@ -304,7 +308,8 @@ public class LogicalDisplayTest {
mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
- /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true,
+ /*isSyncedResolutionSwitchEnabled=*/ true);
// In case of Anisotropy of pixels, then the content should be rescaled so it would adjust
// to using the whole screen. This is because display will rescale it back to fill the
@@ -379,11 +384,24 @@ public class LogicalDisplayTest {
}
@Test
+ public void testSetDisplaySizeIsCalledDuringConfigureDisplayLocked() {
+ mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
+ /*isAnisotropyCorrectionEnabled=*/ true,
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true,
+ /*isSyncedResolutionSwitchEnabled=*/ true);
+ mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
+ SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
+ verify(mDisplayDevice).configureDisplaySizeLocked(eq(t));
+ }
+
+ @Test
public void testGetDisplayPositionAlwaysRotateDisplayEnabled() {
mDisplayDeviceInfo.type = Display.TYPE_EXTERNAL;
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
/*isAnisotropyCorrectionEnabled=*/ true,
- /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true,
+ /*isSyncedResolutionSwitchEnabled=*/ true);
mLogicalDisplay.updateLocked(mDeviceRepo, mSyntheticModeManager);
Point expectedPosition = new Point();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 2cd105ba5317..67b26c1c0b00 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -60,6 +60,8 @@ import android.content.ComponentName;
import android.content.pm.PackageManagerInternal;
import android.net.Uri;
import android.os.SystemClock;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.MediaStore;
import android.util.SparseIntArray;
@@ -71,6 +73,7 @@ import com.android.server.job.JobSchedulerService;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -92,6 +95,9 @@ public class JobStatusTest {
private static final Uri IMAGES_MEDIA_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
private static final Uri VIDEO_MEDIA_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Mock
private JobSchedulerInternal mJobSchedulerInternal;
private MockitoSession mMockingSession;
@@ -1373,6 +1379,86 @@ public class JobStatusTest {
assertEquals("@TestNamespace@TestTag:foo", jobStatus.getBatteryName());
}
+ @Test
+ @EnableFlags({
+ com.android.server.job.Flags.FLAG_INCLUDE_TRACE_TAG_IN_JOB_NAME,
+ android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS
+ })
+ public void testJobName_NotTagNoNamespace_IncludeTraceTagInJobNameEnabled() {
+ JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setTraceTag("TestTraceTag")
+ .build();
+ JobStatus jobStatus = createJobStatus(jobInfo, null, -1, null, null);
+ assertEquals("#TestTraceTag#foo/bar", jobStatus.getBatteryName());
+ }
+
+ @Test
+ @EnableFlags({
+ com.android.server.job.Flags.FLAG_INCLUDE_TRACE_TAG_IN_JOB_NAME,
+ android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS
+ })
+ public void testJobName_NoTagWithNamespace_IncludeTraceTagInJobNameEnabled() {
+ JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setTraceTag("TestTraceTag")
+ .build();
+ JobStatus jobStatus = createJobStatus(jobInfo, null, -1, "TestNamespace", null);
+ assertEquals("#TestTraceTag#@TestNamespace@foo/bar", jobStatus.getBatteryName());
+ }
+
+ @Test
+ @EnableFlags({
+ com.android.server.job.Flags.FLAG_INCLUDE_TRACE_TAG_IN_JOB_NAME,
+ android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS
+ })
+ public void testJobName_WithTagNoNamespace_IncludeTraceTagInJobNameEnabled() {
+ JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setTraceTag("TestTraceTag")
+ .build();
+ JobStatus jobStatus = createJobStatus(jobInfo, SOURCE_PACKAGE, 0, null, "TestTag");
+ assertEquals("#TestTraceTag#TestTag:foo", jobStatus.getBatteryName());
+ }
+
+ @Test
+ @EnableFlags({
+ com.android.server.job.Flags.FLAG_INCLUDE_TRACE_TAG_IN_JOB_NAME,
+ android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS
+ })
+ public void testJobName_FilteredTraceTagEmail_IncludeTraceTagInJobNameEnabled() {
+ JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setTraceTag("test@email.com")
+ .build();
+ JobStatus jobStatus = createJobStatus(jobInfo, SOURCE_PACKAGE, 0, null, "TestTag");
+ assertEquals("#[EMAIL]#TestTag:foo", jobStatus.getBatteryName());
+ }
+
+ @Test
+ @EnableFlags({
+ com.android.server.job.Flags.FLAG_INCLUDE_TRACE_TAG_IN_JOB_NAME,
+ android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS
+ })
+ public void testJobName_FilteredTraceTagPhone_IncludeTraceTagInJobNameEnabled() {
+ JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setTraceTag("123-456-7890")
+ .build();
+ JobStatus jobStatus = createJobStatus(jobInfo, SOURCE_PACKAGE, 0, null, "TestTag");
+ assertEquals("#[PHONE]#TestTag:foo", jobStatus.getBatteryName());
+ }
+
+ @Test
+ @EnableFlags({
+ com.android.server.job.Flags.FLAG_INCLUDE_TRACE_TAG_IN_JOB_NAME,
+ android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS
+ })
+ public void testJobName_WithTagAndNamespace_IncludeTraceTagInJobNameEnabled() {
+ JobInfo jobInfo =
+ new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setTraceTag("TestTraceTag")
+ .build();
+ JobStatus jobStatus =
+ createJobStatus(jobInfo, SOURCE_PACKAGE, 0, "TestNamespace", "TestTag");
+ assertEquals("#TestTraceTag#@TestNamespace@TestTag:foo", jobStatus.getBatteryName());
+ }
+
private void markExpeditedQuotaApproved(JobStatus job, boolean isApproved) {
if (job.isRequestedExpeditedJob()) {
job.setExpeditedJobQuotaApproved(sElapsedRealtimeClock.millis(), isApproved);
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index 83a390d7f70b..4e56422ec391 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -437,6 +437,42 @@ public class NotifierTest {
}
@Test
+ public void testOnGroupChanged_perDisplayWakeByTouchEnabled() {
+ createNotifier();
+ // GIVEN per-display wake by touch is enabled and one display group has been defined with
+ // two displays
+ when(mPowerManagerFlags.isPerDisplayWakeByTouchEnabled()).thenReturn(true);
+ final int groupId = 121;
+ final int displayId1 = 1221;
+ final int displayId2 = 1222;
+ final int[] displays = new int[]{displayId1, displayId2};
+ when(mDisplayManagerInternal.getDisplayIds()).thenReturn(IntArray.wrap(displays));
+ when(mDisplayManagerInternal.getDisplayIdsForGroup(groupId)).thenReturn(displays);
+ SparseArray<int[]> displayIdsByGroupId = new SparseArray<>();
+ displayIdsByGroupId.put(groupId, displays);
+ when(mDisplayManagerInternal.getDisplayIdsByGroupsIds()).thenReturn(displayIdsByGroupId);
+ mNotifier.onGroupWakefulnessChangeStarted(
+ groupId, WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_TAP, /* eventTime= */ 1000);
+ final SparseBooleanArray expectedDisplayInteractivities = new SparseBooleanArray();
+ expectedDisplayInteractivities.put(displayId1, true);
+ expectedDisplayInteractivities.put(displayId2, true);
+ verify(mInputManagerInternal).setDisplayInteractivities(expectedDisplayInteractivities);
+
+ // WHEN display group is changed to only contain one display
+ SparseArray<int[]> newDisplayIdsByGroupId = new SparseArray<>();
+ newDisplayIdsByGroupId.put(groupId, new int[]{displayId1});
+ when(mDisplayManagerInternal.getDisplayIdsByGroupsIds()).thenReturn(newDisplayIdsByGroupId);
+ mNotifier.onGroupChanged();
+
+ // THEN native input manager is informed that the displays in the group have changed
+ final SparseBooleanArray expectedDisplayInteractivitiesAfterChange =
+ new SparseBooleanArray();
+ expectedDisplayInteractivitiesAfterChange.put(displayId1, true);
+ verify(mInputManagerInternal).setDisplayInteractivities(
+ expectedDisplayInteractivitiesAfterChange);
+ }
+
+ @Test
public void testOnWakeLockReleased_FrameworkStatsLogged_NoChains() {
when(mPowerManagerFlags.isMoveWscLoggingToNotifierEnabled()).thenReturn(true);
createNotifier();
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index 29a17e1c85ab..ff6796561926 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -2501,6 +2501,49 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testMultiDisplay_twoDisplays_onlyDefaultDisplayCanDream() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+ when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ setMinimumScreenOffTimeoutConfig(5);
+ createService();
+ startSystem();
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ advanceTime(15000);
+
+ // Only the default display group is dreaming.
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_DREAMING);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_DOZING);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ }
+
+ @Test
public void testMultiDisplay_addNewDisplay_becomeGloballyAwakeButDefaultRemainsDozing() {
final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
diff --git a/services/tests/powerstatstests/res/raw/battery-history.zip b/services/tests/powerstatstests/res/raw/battery-history.zip
new file mode 100644
index 000000000000..ed82ac0f79cc
--- /dev/null
+++ b/services/tests/powerstatstests/res/raw/battery-history.zip
Binary files differ
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java
new file mode 100644
index 000000000000..8fc8c9f677a6
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2025 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.power.stats;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.BatteryConsumer;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.ConditionVariable;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+
+import com.android.internal.os.Clock;
+import com.android.internal.os.CpuScalingPolicies;
+import com.android.internal.os.CpuScalingPolicyReader;
+import com.android.internal.os.MonotonicClock;
+import com.android.internal.os.PowerProfile;
+import com.android.server.power.stats.processor.MultiStatePowerAttributor;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+@android.platform.test.annotations.DisabledOnRavenwood(reason = "Performance test")
+@Ignore("Performance experiment. Comment out @Ignore to run")
+public class BatteryUsageStatsProviderPerfTest {
+ @Rule
+ public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private final Clock mClock = new MockClock();
+ private MonotonicClock mMonotonicClock;
+ private PowerProfile mPowerProfile;
+ private CpuScalingPolicies mCpuScalingPolicies;
+ private File mDirectory;
+ private Handler mHandler;
+ private MockBatteryStatsImpl mBatteryStats;
+
+ @Before
+ public void setup() throws Exception {
+ Context context = InstrumentationRegistry.getContext();
+ mPowerProfile = new PowerProfile(context);
+ mCpuScalingPolicies = new CpuScalingPolicyReader().read();
+
+ HandlerThread mHandlerThread = new HandlerThread("batterystats-handler");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+
+ // Extract accumulated battery history to ensure consistent iterations
+ mDirectory = Files.createTempDirectory("BatteryUsageStatsProviderPerfTest").toFile();
+ File historyDirectory = new File(mDirectory, "battery-history");
+ historyDirectory.mkdir();
+
+ long maxMonotonicTime = 0;
+
+ // To recreate battery-history.zip if necessary, perform these commands:
+ // cd /tmp
+ // mkdir battery-history
+ // adb pull /data/system/battery-history
+ // zip battery-history.zip battery-history/*
+ // cp battery-history.zip \
+ // $ANDROID_BUILD_TOP/frameworks/base/services/tests/powerstatstests/res/raw
+ Resources resources = context.getResources();
+ int resId = resources.getIdentifier("battery-history", "raw", context.getPackageName());
+ try (InputStream in = resources.openRawResource(resId)) {
+ try (ZipInputStream zis = new ZipInputStream(in)) {
+ ZipEntry ze;
+ while ((ze = zis.getNextEntry()) != null) {
+ if (!ze.getName().endsWith(".bh")) {
+ continue;
+ }
+ File file = new File(mDirectory, ze.getName());
+ try (OutputStream out = new FileOutputStream(
+ file)) {
+ FileUtils.copy(zis, out);
+ }
+ long timestamp = Long.parseLong(file.getName().replace(".bh", ""));
+ if (timestamp > maxMonotonicTime) {
+ maxMonotonicTime = timestamp;
+ }
+ }
+ }
+ }
+
+ mMonotonicClock = new MonotonicClock(maxMonotonicTime + 1000000000, mClock);
+ mBatteryStats = new MockBatteryStatsImpl(mClock, mDirectory);
+ }
+
+ @Test
+ public void getBatteryUsageStats_accumulated() {
+ BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
+ .setMaxStatsAgeMs(0)
+ .includePowerStateData()
+ .includeScreenStateData()
+ .includeProcessStateData()
+ .accumulated()
+ .build();
+
+ double expectedCpuPower = 0;
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+
+ waitForBackgroundThread();
+
+ BatteryUsageStatsProvider provider = createBatteryUsageStatsProvider();
+ state.resumeTiming();
+
+ BatteryUsageStats stats = provider.getBatteryUsageStats(mBatteryStats, query);
+ waitForBackgroundThread();
+
+ state.pauseTiming();
+
+ double cpuConsumedPower = stats.getAggregateBatteryConsumer(
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU);
+ assertThat(cpuConsumedPower).isNonZero();
+ if (expectedCpuPower == 0) {
+ expectedCpuPower = cpuConsumedPower;
+ } else {
+ // Verify that all iterations produce the same result
+ assertThat(cpuConsumedPower).isEqualTo(expectedCpuPower);
+ }
+ state.resumeTiming();
+ }
+ }
+
+ private BatteryUsageStatsProvider createBatteryUsageStatsProvider() {
+ Context context = InstrumentationRegistry.getContext();
+
+ PowerStatsStore store = new PowerStatsStore(mDirectory, mHandler);
+ store.reset();
+
+ MultiStatePowerAttributor powerAttributor = new MultiStatePowerAttributor(context, store,
+ mPowerProfile, mCpuScalingPolicies, mPowerProfile::getBatteryCapacity);
+ return new BatteryUsageStatsProvider(context, powerAttributor, mPowerProfile,
+ mCpuScalingPolicies, store, 10000000, mClock, mMonotonicClock);
+ }
+
+ private void waitForBackgroundThread() {
+ ConditionVariable done = new ConditionVariable();
+ mHandler.post(done::open);
+ done.block();
+ }
+}
diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java
index 298d27e2e8c4..879aa4893802 100644
--- a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java
+++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java
@@ -17,7 +17,6 @@
package com.android.server.security.intrusiondetection;
import static android.Manifest.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE;
-import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE;
import static android.Manifest.permission.READ_INTRUSION_DETECTION_STATE;
@@ -28,7 +27,6 @@ import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@@ -37,8 +35,8 @@ import static org.mockito.Mockito.verify;
import android.annotation.SuppressLint;
import android.app.admin.ConnectEvent;
+import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DnsEvent;
-import android.app.admin.SecurityLog;
import android.app.admin.SecurityLog.SecurityEvent;
import android.content.ComponentName;
import android.content.Context;
@@ -53,37 +51,22 @@ import android.os.test.TestLooper;
import android.security.intrusiondetection.IIntrusionDetectionServiceCommandCallback;
import android.security.intrusiondetection.IIntrusionDetectionServiceStateCallback;
import android.security.intrusiondetection.IntrusionDetectionEvent;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.multiuser.annotations.RequireRunOnSystemUser;
-import com.android.bedstead.nene.TestApis;
-import com.android.bedstead.nene.devicepolicy.DeviceOwner;
import com.android.bedstead.permissions.CommonPermissions;
-import com.android.bedstead.permissions.PermissionContext;
import com.android.bedstead.permissions.annotations.EnsureHasPermission;
import com.android.coretests.apps.testapp.LocalIntrusionDetectionEventTransport;
import com.android.server.ServiceThread;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.security.GeneralSecurityException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
+
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -107,7 +90,6 @@ public class IntrusionDetectionServiceTest {
private static final int ERROR_DATA_SOURCE_UNAVAILABLE =
IIntrusionDetectionServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
- private static DeviceOwner sDeviceOwner;
private Context mContext;
private IntrusionDetectionEventTransportConnection mIntrusionDetectionEventTransportConnection;
@@ -124,6 +106,8 @@ public class IntrusionDetectionServiceTest {
"com.android.coretests.apps.testapp";
private static final String TEST_SERVICE = TEST_PKG + ".TestLoggingService";
+ DevicePolicyManagerInternal mDevicePolicyManagerInternal;
+
@SuppressLint("VisibleForTests")
@Before
public void setUp() throws Exception {
@@ -189,6 +173,7 @@ public class IntrusionDetectionServiceTest {
}
@Test
+ @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
public void testAddStateCallback_Disabled_TwoStateCallbacks() throws RemoteException {
StateCallback scb1 = new StateCallback();
assertEquals(STATE_UNKNOWN, scb1.mState);
@@ -204,7 +189,7 @@ public class IntrusionDetectionServiceTest {
}
@Test
- @Ignore("Unit test does not run as system service UID")
+ @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
public void testRemoveStateCallback() throws RemoteException {
mIntrusionDetectionService.setState(STATE_DISABLED);
StateCallback scb1 = new StateCallback();
@@ -220,15 +205,19 @@ public class IntrusionDetectionServiceTest {
mIntrusionDetectionService.getBinderService().removeStateCallback(scb2);
CommandCallback ccb = new CommandCallback();
+
+ // Enable will fail; caller does not run as system server.
+ doNothing().when(mDataAggregator).enable();
mIntrusionDetectionService.getBinderService().enable(ccb);
+
mTestLooper.dispatchAll();
assertEquals(STATE_ENABLED, scb1.mState);
assertEquals(STATE_DISABLED, scb2.mState);
assertNull(ccb.mErrorCode);
}
- @Ignore("Unit test does not run as system service UID")
@Test
+ @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
public void testEnable_FromDisabled_TwoStateCallbacks() throws RemoteException {
mIntrusionDetectionService.setState(STATE_DISABLED);
StateCallback scb1 = new StateCallback();
@@ -243,6 +232,9 @@ public class IntrusionDetectionServiceTest {
CommandCallback ccb = new CommandCallback();
mIntrusionDetectionService.getBinderService().enable(ccb);
+
+ // Enable will fail; caller does not run as system server.
+ doNothing().when(mDataAggregator).enable();
mTestLooper.dispatchAll();
verify(mDataAggregator, times(1)).enable();
@@ -319,7 +311,7 @@ public class IntrusionDetectionServiceTest {
assertNull(ccb.mErrorCode);
}
- @Ignore("Enable once the IntrusionDetectionEventTransportConnection is ready")
+ @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
@Test
public void testEnable_FromDisable_TwoStateCallbacks_TransportUnavailable()
throws RemoteException {
@@ -390,146 +382,6 @@ public class IntrusionDetectionServiceTest {
}
@Test
- @Ignore("Unit test does not run as system service UID")
- @RequireRunOnSystemUser
- @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
- public void testDataAggregator_AddSecurityEvent() throws Exception {
- mIntrusionDetectionService.setState(STATE_ENABLED);
- ServiceThread mockThread = spy(ServiceThread.class);
- mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
-
- // SecurityLogging generates a number of events and callbacks, so create a latch to wait for
- // the given event.
- String eventString = this.getClass().getName() + ".testSecurityEvent";
-
- final CountDownLatch latch = new CountDownLatch(1);
- // TODO: Replace this mock when the IntrusionDetectionEventTransportConnection is ready.
- doAnswer(
- new Answer<Boolean>() {
- @Override
- public Boolean answer(InvocationOnMock input) {
- List<IntrusionDetectionEvent> receivedEvents =
- (List<IntrusionDetectionEvent>) input.getArguments()[0];
- for (IntrusionDetectionEvent event : receivedEvents) {
- if (event.getType() == IntrusionDetectionEvent.SECURITY_EVENT) {
- SecurityEvent securityEvent = event.getSecurityEvent();
- Object[] eventData = (Object[]) securityEvent.getData();
- if (securityEvent.getTag() == SecurityLog.TAG_KEY_GENERATED
- && eventData[1].equals(eventString)) {
- latch.countDown();
- }
- }
- }
- return true;
- }
- })
- .when(mIntrusionDetectionEventTransportConnection).addData(any());
- mDataAggregator.enable();
-
- // Generate the security event.
- generateSecurityEvent(eventString);
- TestApis.devicePolicy().forceSecurityLogs();
-
- // Verify the event is received.
- mTestLooper.startAutoDispatch();
- assertTrue(latch.await(1, TimeUnit.SECONDS));
- mTestLooper.stopAutoDispatch();
-
- mDataAggregator.disable();
- }
-
- @Test
- @RequireRunOnSystemUser
- @Ignore("Unit test does not run as system service UID")
- @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING)
- public void testDataAggregator_AddNetworkEvent() throws Exception {
- mIntrusionDetectionService.setState(STATE_ENABLED);
- ServiceThread mockThread = spy(ServiceThread.class);
- mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
-
- // Network logging may log multiple and callbacks, so create a latch to wait for
- // the given event.
- // eventServer must be a valid domain to generate a network log event.
- String eventServer = "google.com";
- final CountDownLatch latch = new CountDownLatch(1);
- // TODO: Replace this mock when the IntrusionDetectionEventTransportConnection is ready.
- doAnswer(
- new Answer<Boolean>() {
- @Override
- public Boolean answer(InvocationOnMock input) {
- List<IntrusionDetectionEvent> receivedEvents =
- (List<IntrusionDetectionEvent>) input.getArguments()[0];
- for (IntrusionDetectionEvent event : receivedEvents) {
- if (event.getType()
- == IntrusionDetectionEvent.NETWORK_EVENT_DNS) {
- DnsEvent dnsEvent = event.getDnsEvent();
- if (dnsEvent.getHostname().equals(eventServer)) {
- latch.countDown();
- }
- }
- }
- return true;
- }
- })
- .when(mIntrusionDetectionEventTransportConnection).addData(any());
- mDataAggregator.enable();
-
- // Generate the network event.
- generateNetworkEvent(eventServer);
- TestApis.devicePolicy().forceNetworkLogs();
-
- // Verify the event is received.
- mTestLooper.startAutoDispatch();
- assertTrue(latch.await(1, TimeUnit.SECONDS));
- mTestLooper.stopAutoDispatch();
-
- mDataAggregator.disable();
- }
-
- /** Emits a given string into security log (if enabled). */
- private void generateSecurityEvent(String eventString)
- throws IllegalArgumentException, GeneralSecurityException, IOException {
- if (eventString == null || eventString.isEmpty()) {
- throw new IllegalArgumentException(
- "Error generating security event: eventString must not be empty");
- }
-
- final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
- keyGen.initialize(
- new KeyGenParameterSpec.Builder(eventString, KeyProperties.PURPOSE_SIGN).build());
- // Emit key generation event.
- final KeyPair keyPair = keyGen.generateKeyPair();
- assertNotNull(keyPair);
-
- final KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
- ks.load(null);
- // Emit key destruction event.
- ks.deleteEntry(eventString);
- }
-
- /** Emits a given string into network log (if enabled). */
- private void generateNetworkEvent(String server) throws IllegalArgumentException, IOException {
- if (server == null || server.isEmpty()) {
- throw new IllegalArgumentException(
- "Error generating network event: server must not be empty");
- }
-
- HttpURLConnection urlConnection = null;
- int connectionTimeoutMS = 2_000;
- try (PermissionContext p = TestApis.permissions().withPermission(INTERNET)) {
- final URL url = new URL("http://" + server);
- urlConnection = (HttpURLConnection) url.openConnection();
- urlConnection.setConnectTimeout(connectionTimeoutMS);
- urlConnection.setReadTimeout(connectionTimeoutMS);
- urlConnection.getResponseCode();
- } finally {
- if (urlConnection != null) {
- urlConnection.disconnect();
- }
- }
- }
-
- @Test
@RequireRunOnSystemUser
@EnsureHasPermission(
android.Manifest.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
index 0227ef1d2dc0..7f60caaa569b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java
@@ -326,6 +326,80 @@ public class AutoclickControllerTest {
assertThat(mController.mClickScheduler.getIsActiveForTesting()).isTrue();
}
+ @Test
+ public void smallJitteryMovement_doesNotTriggerClick() {
+ // Initial hover move to set an anchor point.
+ MotionEvent initialHoverMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 100,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 30f,
+ /* y= */ 40f,
+ /* metaState= */ 0);
+ initialHoverMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(initialHoverMove, initialHoverMove, /* policyFlags= */ 0);
+
+ // Get the initial scheduled click time.
+ long initialScheduledTime = mController.mClickScheduler.getScheduledClickTimeForTesting();
+
+ // Simulate small, jittery movements (all within the default slop).
+ MotionEvent jitteryMove1 = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 150,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 31f, // Small change in x
+ /* y= */ 41f, // Small change in y
+ /* metaState= */ 0);
+ jitteryMove1.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(jitteryMove1, jitteryMove1, /* policyFlags= */ 0);
+
+ MotionEvent jitteryMove2 = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 200,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 30.5f, // Small change in x
+ /* y= */ 39.8f, // Small change in y
+ /* metaState= */ 0);
+ jitteryMove2.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(jitteryMove2, jitteryMove2, /* policyFlags= */ 0);
+
+ // Verify that the scheduled click time has NOT changed.
+ assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting())
+ .isEqualTo(initialScheduledTime);
+ }
+
+ @Test
+ public void singleSignificantMovement_triggersClick() {
+ // Initial hover move to set an anchor point.
+ MotionEvent initialHoverMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 100,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 30f,
+ /* y= */ 40f,
+ /* metaState= */ 0);
+ initialHoverMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(initialHoverMove, initialHoverMove, /* policyFlags= */ 0);
+
+ // Get the initial scheduled click time.
+ long initialScheduledTime = mController.mClickScheduler.getScheduledClickTimeForTesting();
+
+ // Simulate a single, significant movement (greater than the default slop).
+ MotionEvent significantMove = MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 150,
+ /* action= */ MotionEvent.ACTION_HOVER_MOVE,
+ /* x= */ 60f, // Significant change in x (30f difference)
+ /* y= */ 70f, // Significant change in y (30f difference)
+ /* metaState= */ 0);
+ significantMove.setSource(InputDevice.SOURCE_MOUSE);
+ mController.onMotionEvent(significantMove, significantMove, /* policyFlags= */ 0);
+
+ // Verify that the scheduled click time has changed (click was rescheduled).
+ assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting())
+ .isNotEqualTo(initialScheduledTime);
+ }
+
private void injectFakeMouseActionHoverMoveEvent() {
MotionEvent event = getFakeMotionHoverMoveEvent();
event.setSource(InputDevice.SOURCE_MOUSE);
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 06958b81d846..1627f683cd3e 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -25,6 +25,7 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
+import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
@@ -115,7 +116,6 @@ import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.UserTypeDetails;
import com.android.server.pm.UserTypeFactory;
-import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerService;
import com.google.common.collect.Range;
@@ -1563,11 +1563,11 @@ public class UserControllerTest {
// and the thread is still alive
assertTrue(threadStartUser.isAlive());
- // mock send the keyguard shown event
- ArgumentCaptor<ActivityTaskManagerInternal.ScreenObserver> captor = ArgumentCaptor.forClass(
- ActivityTaskManagerInternal.ScreenObserver.class);
- verify(mInjector.mActivityTaskManagerInternal).registerScreenObserver(captor.capture());
- captor.getValue().onKeyguardStateChanged(true);
+ // mock the binder response for the user switch completion
+ ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
+ verify(mInjector.mWindowManagerMock).lockNow(captor.capture());
+ IRemoteCallback.Stub.asInterface(captor.getValue().getBinder(
+ LOCK_ON_USER_SWITCH_CALLBACK)).sendResult(null);
// verify the switch now moves on...
Thread.sleep(1000);
@@ -1757,7 +1757,6 @@ public class UserControllerTest {
private final IStorageManager mStorageManagerMock;
private final UserManagerInternal mUserManagerInternalMock;
private final WindowManagerService mWindowManagerMock;
- private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
private final PowerManagerInternal mPowerManagerInternal;
private final AlarmManagerInternal mAlarmManagerInternal;
private final KeyguardManager mKeyguardManagerMock;
@@ -1779,7 +1778,6 @@ public class UserControllerTest {
mUserManagerMock = mock(UserManagerService.class);
mUserManagerInternalMock = mock(UserManagerInternal.class);
mWindowManagerMock = mock(WindowManagerService.class);
- mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
mStorageManagerMock = mock(IStorageManager.class);
mPowerManagerInternal = mock(PowerManagerInternal.class);
mAlarmManagerInternal = mock(AlarmManagerInternal.class);
@@ -1843,11 +1841,6 @@ public class UserControllerTest {
}
@Override
- ActivityTaskManagerInternal getActivityTaskManagerInternal() {
- return mActivityTaskManagerInternal;
- }
-
- @Override
PowerManagerInternal getPowerManagerInternal() {
return mPowerManagerInternal;
}
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceInventoryTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceInventoryTest.java
index b5a538fa09f8..c7da27420cbb 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceInventoryTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceInventoryTest.java
@@ -103,7 +103,7 @@ public class AudioDeviceInventoryTest {
// NOTE: for now this is only when flag asDeviceConnectionFailure is true
if (asDeviceConnectionFailure()) {
when(mSpyAudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_AVAILABLE,
- AudioSystem.AUDIO_FORMAT_DEFAULT))
+ AudioSystem.AUDIO_FORMAT_DEFAULT, false /*deviceSwitch*/))
.thenReturn(AudioSystem.AUDIO_STATUS_ERROR);
runWithBluetoothPrivilegedPermission(
() -> mDevInventory.onSetBtActiveDevice(/*btInfo*/ btInfo,
@@ -115,7 +115,7 @@ public class AudioDeviceInventoryTest {
// test that the device is added when AudioSystem returns AUDIO_STATUS_OK
// when setDeviceConnectionState is called for the connection
when(mSpyAudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_AVAILABLE,
- AudioSystem.AUDIO_FORMAT_DEFAULT))
+ AudioSystem.AUDIO_FORMAT_DEFAULT, false /*deviceSwitch*/))
.thenReturn(AudioSystem.AUDIO_STATUS_OK);
runWithBluetoothPrivilegedPermission(
() -> mDevInventory.onSetBtActiveDevice(/*btInfo*/ btInfo,
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
index ce59a86c6ca3..39e7d727f7c5 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
@@ -51,9 +51,9 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter {
// Overrides of AudioSystemAdapter
@Override
public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
- int codecFormat) {
- Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, 0x%s",
- attributes.toString(), state, Integer.toHexString(codecFormat)));
+ int codecFormat, boolean deviceSwitch) {
+ Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, 0x%s %b",
+ attributes.toString(), state, Integer.toHexString(codecFormat), deviceSwitch));
return AudioSystem.AUDIO_STATUS_OK;
}
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 30aa8cebdff6..e0023e59af50 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1768,6 +1768,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore // b/396073342
public void testCertificateDisclosure() throws Exception {
final int userId = CALLER_USER_HANDLE;
final UserHandle user = UserHandle.of(userId);
@@ -4612,6 +4613,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore // b/396073342
public void testGetLastBugReportRequestTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -4659,6 +4661,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore // b/396073342
public void testGetLastNetworkLogRetrievalTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -6441,6 +6444,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore // b/396073342
public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception {
mServiceContext.packageName = mRealTestContext.getPackageName();
mServiceContext.applicationInfo = new ApplicationInfo();
@@ -6452,6 +6456,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore // b/396073342
public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception {
mServiceContext.packageName = mRealTestContext.getPackageName();
mServiceContext.applicationInfo = new ApplicationInfo();
@@ -6464,6 +6469,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
@Test
+ @Ignore // b/396073342
public void testGetOwnerInstalledCaCertsForDelegate() throws Exception {
mServiceContext.packageName = mRealTestContext.getPackageName();
mServiceContext.applicationInfo = new ApplicationInfo();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
index fca0cfbc7d2f..cf2c15c5daca 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
@@ -432,7 +432,7 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
.setMaxVolumeIndex(AudioStatus.MAX_VOLUME)
.setMinVolumeIndex(AudioStatus.MIN_VOLUME)
.build()),
- any(), any(), anyBoolean());
+ anyBoolean(), any(), any());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
index ec44a918f8e8..f44517a47f55 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
@@ -112,7 +112,7 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
.setMaxVolumeIndex(AudioStatus.MAX_VOLUME)
.setMinVolumeIndex(AudioStatus.MIN_VOLUME)
.build()),
- any(), any(), anyBoolean());
+ anyBoolean(), any(), any());
}
@@ -135,7 +135,7 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
.setMaxVolumeIndex(AudioStatus.MAX_VOLUME)
.setMinVolumeIndex(AudioStatus.MIN_VOLUME)
.build()),
- any(), any(), anyBoolean());
+ anyBoolean(), any(), any());
}
@Test
@@ -160,7 +160,7 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
.setMaxVolumeIndex(AudioStatus.MAX_VOLUME)
.setMinVolumeIndex(AudioStatus.MIN_VOLUME)
.build()),
- any(), any(), anyBoolean());
+ anyBoolean(), any(), any());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java
index 7294ba62cdae..90f94cb4b596 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java
@@ -183,9 +183,9 @@ public class FakeAudioFramework {
public void setDeviceAbsoluteVolumeBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull VolumeInfo volume,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment) {
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
setVolumeBehaviorHelper(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
}
@@ -193,9 +193,9 @@ public class FakeAudioFramework {
public void setDeviceAbsoluteVolumeAdjustOnlyBehavior(
@NonNull AudioDeviceAttributes device,
@NonNull VolumeInfo volume,
+ boolean handlesVolumeAdjustment,
@NonNull @CallbackExecutor Executor executor,
- @NonNull OnAudioDeviceVolumeChangedListener vclistener,
- boolean handlesVolumeAdjustment) {
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
setVolumeBehaviorHelper(device,
AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index f74e2ace7ae3..563baacf5811 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -66,6 +66,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -1033,6 +1034,7 @@ public class HdmiCecLocalDeviceTvTest {
}
@Test
+ @Ignore("b/360768278")
public void onHotplug_doNotSend_systemAudioModeRequestWithParameter(){
// Add a device to the network and assert that this device is included in the list of
// devices.
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 0eb20eb22380..66d7611a29c6 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -32,6 +32,7 @@ android_test {
"androidx.test.rules",
"hamcrest-library",
"mockito-target-inline-minus-junit4",
+ "mockito-target-extended",
"platform-compat-test-rules",
"platform-test-annotations",
"platformprotosnano",
diff --git a/services/tests/uiservicestests/src/android/app/NotificationManagerZenTest.java b/services/tests/uiservicestests/src/android/app/NotificationManagerZenTest.java
index 779fa1aa2f72..dbbe40fd42e6 100644
--- a/services/tests/uiservicestests/src/android/app/NotificationManagerZenTest.java
+++ b/services/tests/uiservicestests/src/android/app/NotificationManagerZenTest.java
@@ -80,7 +80,7 @@ public class NotificationManagerZenTest {
}
@Test
- @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @RequiresFlagsEnabled(Flags.FLAG_MODES_UI)
public void setAutomaticZenRuleState_manualActivation() {
AutomaticZenRule ruleToCreate = createZenRule("rule");
String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
@@ -111,7 +111,7 @@ public class NotificationManagerZenTest {
}
@Test
- @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @RequiresFlagsEnabled(Flags.FLAG_MODES_UI)
public void setAutomaticZenRuleState_manualDeactivation() {
AutomaticZenRule ruleToCreate = createZenRule("rule");
String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
@@ -145,7 +145,7 @@ public class NotificationManagerZenTest {
}
@Test
- @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @RequiresFlagsEnabled(Flags.FLAG_MODES_UI)
public void setAutomaticZenRuleState_respectsManuallyActivated() {
AutomaticZenRule ruleToCreate = createZenRule("rule");
String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
@@ -178,7 +178,7 @@ public class NotificationManagerZenTest {
}
@Test
- @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @RequiresFlagsEnabled(Flags.FLAG_MODES_UI)
public void setAutomaticZenRuleState_respectsManuallyDeactivated() {
AutomaticZenRule ruleToCreate = createZenRule("rule");
String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
@@ -212,7 +212,7 @@ public class NotificationManagerZenTest {
}
@Test
- @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @RequiresFlagsEnabled(Flags.FLAG_MODES_UI)
public void setAutomaticZenRuleState_manualActivationFromApp() {
AutomaticZenRule ruleToCreate = createZenRule("rule");
String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
@@ -244,7 +244,7 @@ public class NotificationManagerZenTest {
}
@Test
- @RequiresFlagsEnabled({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @RequiresFlagsEnabled(Flags.FLAG_MODES_UI)
public void setAutomaticZenRuleState_manualDeactivationFromApp() {
AutomaticZenRule ruleToCreate = createZenRule("rule");
String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate);
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index c4b8599a483c..9930c9f07ed8 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -70,7 +70,6 @@ import android.Manifest;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlarmManager;
-import android.app.Flags;
import android.app.IOnProjectionStateChangedListener;
import android.app.IUiModeManager;
import android.content.BroadcastReceiver;
@@ -91,7 +90,6 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.test.FakePermissionEnforcer;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
@@ -1508,13 +1506,11 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void testAttentionModeThemeOverlay_nightModeDisabled() throws RemoteException {
testAttentionModeThemeOverlay(false);
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void testAttentionModeThemeOverlay_nightModeEnabled() throws RemoteException {
testAttentionModeThemeOverlay(true);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
index b3ec2153542a..c9d5241c57b7 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
@@ -30,6 +30,7 @@ import android.testing.TestableContext;
import androidx.test.InstrumentationRegistry;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import org.junit.After;
@@ -41,6 +42,7 @@ import org.mockito.MockitoAnnotations;
public class UiServiceTestCase {
@Mock protected PackageManagerInternal mPmi;
+ @Mock protected UserManagerInternal mUmi;
@Mock protected UriGrantsManagerInternal mUgmInternal;
protected static final String PKG_N_MR1 = "com.example.n_mr1";
@@ -92,6 +94,8 @@ public class UiServiceTestCase {
}
});
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, mUmi);
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
when(mUgmInternal.checkGrantUriPermission(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java b/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java
index 1890879da69d..5ce9a3e8d4d4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java
@@ -47,7 +47,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.display.ColorDisplayManager;
import android.os.PowerManager;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenDeviceEffects;
import android.testing.TestableContext;
@@ -102,8 +101,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_appliesEffects() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
.setShouldSuppressAmbientDisplay(true)
.setShouldDimWallpaper(true)
@@ -119,7 +116,6 @@ public class DefaultDeviceEffectsApplierTest {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void apply_logsToZenLog() {
when(mPowerManager.isInteractive()).thenReturn(true);
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
@@ -155,8 +151,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_removesEffects() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
ZenDeviceEffects previousEffects = new ZenDeviceEffects.Builder()
.setShouldSuppressAmbientDisplay(true)
.setShouldDimWallpaper(true)
@@ -180,8 +174,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_removesOnlyPreviouslyAppliedEffects() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
ZenDeviceEffects previousEffects = new ZenDeviceEffects.Builder()
.setShouldSuppressAmbientDisplay(true)
.build();
@@ -197,7 +189,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_missingSomeServices_okay() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mContext.addMockSystemService(ColorDisplayManager.class, null);
mContext.addMockSystemService(WallpaperManager.class, null);
mApplier = new DefaultDeviceEffectsApplier(mContext);
@@ -216,7 +207,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_disabledWallpaperService_dimWallpaperNotApplied() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
WallpaperManager disabledWallpaperService = mock(WallpaperManager.class);
when(mWallpaperManager.isWallpaperSupported()).thenReturn(false);
mContext.addMockSystemService(WallpaperManager.class, disabledWallpaperService);
@@ -236,8 +226,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_someEffects_onlyThoseEffectsApplied() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
.setShouldDimWallpaper(true)
.setShouldDisplayGrayscale(true)
@@ -253,8 +241,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_onlyEffectDeltaApplied() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
mApplier.apply(new ZenDeviceEffects.Builder().setShouldDimWallpaper(true).build(),
ORIGIN_USER_IN_SYSTEMUI);
verify(mWallpaperManager).setWallpaperDimAmount(eq(0.6f));
@@ -272,7 +258,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_nightModeFromApp_appliedOnScreenOff() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
ArgumentCaptor<IntentFilter> intentFilterCaptor =
@@ -301,8 +286,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_nightModeWithScreenOff_appliedImmediately(
@TestParameter ZenChangeOrigin origin) {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
when(mPowerManager.isInteractive()).thenReturn(false);
mApplier.apply(new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build(),
@@ -314,7 +297,6 @@ public class DefaultDeviceEffectsApplierTest {
}
@Test
- @EnableFlags({android.app.Flags.FLAG_MODES_API, android.app.Flags.FLAG_MODES_UI})
public void apply_nightModeWithScreenOnAndKeyguardShowing_appliedImmediately(
@TestParameter ZenChangeOrigin origin) {
@@ -334,8 +316,6 @@ public class DefaultDeviceEffectsApplierTest {
"{origin: ORIGIN_INIT}", "{origin: ORIGIN_INIT_USER}"})
public void apply_nightModeWithScreenOn_appliedImmediatelyBasedOnOrigin(
ZenChangeOrigin origin) {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
when(mPowerManager.isInteractive()).thenReturn(true);
mApplier.apply(new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build(),
@@ -351,8 +331,6 @@ public class DefaultDeviceEffectsApplierTest {
"{origin: ORIGIN_SYSTEM}", "{origin: ORIGIN_UNKNOWN}"})
public void apply_nightModeWithScreenOn_willBeAppliedLaterBasedOnOrigin(
ZenChangeOrigin origin) {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
when(mPowerManager.isInteractive()).thenReturn(true);
mApplier.apply(new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build(),
@@ -367,8 +345,6 @@ public class DefaultDeviceEffectsApplierTest {
@Test
public void apply_servicesThrow_noCrash() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
doThrow(new RuntimeException()).when(mPowerManager)
.suppressAmbientDisplay(anyString(), anyBoolean());
doThrow(new RuntimeException()).when(mColorDisplayManager).setSaturationLevel(anyInt());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index e5c42082ab97..98440ecdad82 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -17,12 +17,17 @@ package com.android.server.notification;
import static android.content.Context.DEVICE_POLICY_SERVICE;
import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR;
+import static android.os.UserHandle.USER_ALL;
+import static android.os.UserHandle.USER_CURRENT;
import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_AUTOBIND;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.notification.Flags.FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER;
+import static com.android.server.notification.Flags.managedServicesConcurrentMultiuser;
import static com.android.server.notification.ManagedServices.APPROVAL_BY_COMPONENT;
import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAGE;
import static com.android.server.notification.NotificationManagerService.privateSpaceFlagsEnabled;
@@ -66,7 +71,9 @@ import android.os.IInterface;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -83,6 +90,7 @@ import com.android.server.UiServiceTestCase;
import com.google.android.collect.Lists;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -105,6 +113,9 @@ import java.util.concurrent.CountDownLatch;
public class ManagedServicesTest extends UiServiceTestCase {
+ @Rule
+ public SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Mock
private IPackageManager mIpm;
@Mock
@@ -155,6 +166,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
users.add(new UserInfo(11, "11", 0));
users.add(new UserInfo(12, "12", 0));
users.add(new UserInfo(13, "13", 0));
+ users.add(new UserInfo(99, "99", 0));
for (UserInfo user : users) {
when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
}
@@ -804,6 +816,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void rebindServices_onlyBindsExactMatchesIfComponent() throws Exception {
// If the primary and secondary lists contain component names, only those components within
// the package should be matched
@@ -841,6 +854,45 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void rebindServices_onlyBindsExactMatchesIfComponent_concurrent_multiUser()
+ throws Exception {
+ // If the primary and secondary lists contain component names, only those components within
+ // the package should be matched
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+ mIpm,
+ ManagedServices.APPROVAL_BY_COMPONENT);
+
+ List<String> packages = new ArrayList<>();
+ packages.add("package");
+ packages.add("anotherPackage");
+ addExpectedServices(service, packages, 0);
+
+ // only 2 components are approved per package
+ mExpectedPrimaryComponentNames.clear();
+ mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
+ mExpectedSecondaryComponentNames.clear();
+ mExpectedSecondaryComponentNames.put(0, "anotherPackage/C1:anotherPackage/C2");
+
+ loadXml(service);
+ // verify the 2 components per package are enabled (bound)
+ verifyExpectedBoundEntries(service, true, 0);
+ verifyExpectedBoundEntries(service, false, 0);
+
+ // verify the last component per package is not enabled/we don't try to bind to it
+ for (String pkg : packages) {
+ ComponentName unapprovedAdditionalComponent =
+ ComponentName.unflattenFromString(pkg + "/C3");
+ assertFalse(
+ service.isComponentEnabledForUser(
+ unapprovedAdditionalComponent, 0));
+ verify(mIpm, never()).getServiceInfo(
+ eq(unapprovedAdditionalComponent), anyLong(), anyInt());
+ }
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void rebindServices_bindsEverythingInAPackage() throws Exception {
// If the primary and secondary lists contain packages, all components within those packages
// should be bound
@@ -866,6 +918,32 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void rebindServices_bindsEverythingInAPackage_concurrent_multiUser() throws Exception {
+ // If the primary and secondary lists contain packages, all components within those packages
+ // should be bound
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_PACKAGE);
+
+ List<String> packages = new ArrayList<>();
+ packages.add("package");
+ packages.add("packagea");
+ addExpectedServices(service, packages, 0);
+
+ // 2 approved packages
+ mExpectedPrimaryPackages.clear();
+ mExpectedPrimaryPackages.put(0, "package");
+ mExpectedSecondaryPackages.clear();
+ mExpectedSecondaryPackages.put(0, "packagea");
+
+ loadXml(service);
+
+ // verify the 3 components per package are enabled (bound)
+ verifyExpectedBoundEntries(service, true, 0);
+ verifyExpectedBoundEntries(service, false, 0);
+ }
+
+ @Test
public void reregisterService_checksAppIsApproved_pkg() throws Exception {
Context context = mock(Context.class);
PackageManager pm = mock(PackageManager.class);
@@ -1118,6 +1196,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void testUpgradeAppBindsNewServices() throws Exception {
// If the primary and secondary lists contain component names, only those components within
// the package should be matched
@@ -1159,6 +1238,49 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testUpgradeAppBindsNewServices_concurrent_multiUser() throws Exception {
+ // If the primary and secondary lists contain component names, only those components within
+ // the package should be matched
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+ mIpm,
+ ManagedServices.APPROVAL_BY_PACKAGE);
+
+ List<String> packages = new ArrayList<>();
+ packages.add("package");
+ addExpectedServices(service, packages, 0);
+
+ // only 2 components are approved per package
+ mExpectedPrimaryComponentNames.clear();
+ mExpectedPrimaryPackages.clear();
+ mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
+ mExpectedSecondaryComponentNames.clear();
+ mExpectedSecondaryPackages.clear();
+
+ loadXml(service);
+
+ // new component expected
+ mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2:package/C3");
+
+ service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});
+
+ // verify the 3 components per package are enabled (bound)
+ verifyExpectedBoundEntries(service, true, 0);
+
+ // verify the last component per package is not enabled/we don't try to bind to it
+ for (String pkg : packages) {
+ ComponentName unapprovedAdditionalComponent =
+ ComponentName.unflattenFromString(pkg + "/C3");
+ assertFalse(
+ service.isComponentEnabledForUser(
+ unapprovedAdditionalComponent, 0));
+ verify(mIpm, never()).getServiceInfo(
+ eq(unapprovedAdditionalComponent), anyLong(), anyInt());
+ }
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void testUpgradeAppNoPermissionNoRebind() throws Exception {
Context context = spy(getContext());
doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());
@@ -1211,6 +1333,59 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testUpgradeAppNoPermissionNoRebind_concurrent_multiUser() throws Exception {
+ Context context = spy(getContext());
+ doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles,
+ mIpm,
+ APPROVAL_BY_COMPONENT);
+
+ List<String> packages = new ArrayList<>();
+ packages.add("package");
+ addExpectedServices(service, packages, 0);
+
+ final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1");
+ final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2");
+
+ // Both components are approved initially
+ mExpectedPrimaryComponentNames.clear();
+ mExpectedPrimaryPackages.clear();
+ mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
+ mExpectedSecondaryComponentNames.clear();
+ mExpectedSecondaryPackages.clear();
+
+ loadXml(service);
+
+ //Component package/C1 loses bind permission
+ when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
+ (Answer<ServiceInfo>) invocation -> {
+ ComponentName invocationCn = invocation.getArgument(0);
+ if (invocationCn != null) {
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = invocationCn.getPackageName();
+ serviceInfo.name = invocationCn.getClassName();
+ if (invocationCn.equals(unapprovedComponent)) {
+ serviceInfo.permission = "none";
+ } else {
+ serviceInfo.permission = service.getConfig().bindPermission;
+ }
+ serviceInfo.metaData = null;
+ return serviceInfo;
+ }
+ return null;
+ }
+ );
+
+ // Trigger package update
+ service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});
+
+ assertFalse(service.isComponentEnabledForUser(unapprovedComponent, 0));
+ assertTrue(service.isComponentEnabledForUser(approvedComponent, 0));
+ }
+
+ @Test
public void testSetPackageOrComponentEnabled() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
@@ -1517,6 +1692,201 @@ public class ManagedServicesTest extends UiServiceTestCase {
assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("c/c")));
}
+ @SuppressWarnings("GuardedBy")
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testPopulateComponentsToBindWithNonProfileUser() {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ spyOn(service);
+
+ SparseArray<ArraySet<ComponentName>> approvedComponentsByUser = new SparseArray<>();
+ ArraySet<ComponentName> allowed0 = new ArraySet<>();
+ allowed0.add(ComponentName.unflattenFromString("a/a"));
+ approvedComponentsByUser.put(0, allowed0);
+ ArraySet<ComponentName> allowed10 = new ArraySet<>();
+ allowed10.add(ComponentName.unflattenFromString("b/b"));
+ approvedComponentsByUser.put(10, allowed10);
+
+ int nonProfileUser = 99;
+ ArraySet<ComponentName> allowedForNonProfileUser = new ArraySet<>();
+ allowedForNonProfileUser.add(ComponentName.unflattenFromString("c/c"));
+ approvedComponentsByUser.put(nonProfileUser, allowedForNonProfileUser);
+
+ IntArray users = new IntArray();
+ users.add(nonProfileUser);
+ users.add(10);
+ users.add(0);
+
+ SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
+ spyOn(service.mUmInternal);
+ when(service.mUmInternal.isVisibleBackgroundFullUser(nonProfileUser)).thenReturn(true);
+
+ service.populateComponentsToBind(componentsToBind, users, approvedComponentsByUser);
+
+ assertTrue(service.isComponentEnabledForUser(
+ ComponentName.unflattenFromString("a/a"), 0));
+ assertTrue(service.isComponentEnabledForPackage("a", 0));
+ assertTrue(service.isComponentEnabledForUser(
+ ComponentName.unflattenFromString("b/b"), 10));
+ assertTrue(service.isComponentEnabledForPackage("b", 0));
+ assertTrue(service.isComponentEnabledForPackage("b", 10));
+ assertTrue(service.isComponentEnabledForUser(
+ ComponentName.unflattenFromString("c/c"), nonProfileUser));
+ assertTrue(service.isComponentEnabledForPackage("c", nonProfileUser));
+ }
+
+
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testRebindService_profileUser() throws Exception {
+ final int profileUserId = 10;
+ when(mUserProfiles.isProfileUser(profileUserId, mContext)).thenReturn(true);
+ spyOn(mService);
+ ArgumentCaptor<IntArray> captor = ArgumentCaptor.forClass(
+ IntArray.class);
+ when(mService.allowRebindForParentUser()).thenReturn(true);
+
+ mService.rebindServices(false, profileUserId);
+
+ verify(mService).populateComponentsToBind(any(), captor.capture(), any());
+ assertTrue(captor.getValue().contains(0));
+ assertTrue(captor.getValue().contains(profileUserId));
+ }
+
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testRebindService_nonProfileUser() throws Exception {
+ final int userId = 99;
+ when(mUserProfiles.isProfileUser(userId, mContext)).thenReturn(false);
+ spyOn(mService);
+ ArgumentCaptor<IntArray> captor = ArgumentCaptor.forClass(
+ IntArray.class);
+ when(mService.allowRebindForParentUser()).thenReturn(true);
+
+ mService.rebindServices(false, userId);
+
+ verify(mService).populateComponentsToBind(any(), captor.capture(), any());
+ assertFalse(captor.getValue().contains(0));
+ assertTrue(captor.getValue().contains(userId));
+ }
+
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testRebindService_userAll() throws Exception {
+ final int userId = 99;
+ spyOn(mService);
+ spyOn(mService.mUmInternal);
+ when(mService.mUmInternal.isVisibleBackgroundFullUser(userId)).thenReturn(true);
+ ArgumentCaptor<IntArray> captor = ArgumentCaptor.forClass(
+ IntArray.class);
+ when(mService.allowRebindForParentUser()).thenReturn(true);
+
+ mService.rebindServices(false, USER_ALL);
+
+ verify(mService).populateComponentsToBind(any(), captor.capture(), any());
+ assertTrue(captor.getValue().contains(0));
+ assertTrue(captor.getValue().contains(userId));
+ }
+
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testOnUserStoppedWithVisibleBackgroundUser() throws Exception {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ spyOn(service);
+ int userId = 99;
+ SparseArray<ArraySet<ComponentName>> approvedComponentsByUser = new SparseArray<>();
+ ArraySet<ComponentName> allowedForNonProfileUser = new ArraySet<>();
+ allowedForNonProfileUser.add(ComponentName.unflattenFromString("a/a"));
+ approvedComponentsByUser.put(userId, allowedForNonProfileUser);
+ IntArray users = new IntArray();
+ users.add(userId);
+ SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
+ spyOn(service.mUmInternal);
+ when(service.mUmInternal.isVisibleBackgroundFullUser(userId)).thenReturn(true);
+ service.populateComponentsToBind(componentsToBind, users, approvedComponentsByUser);
+ assertTrue(service.isComponentEnabledForUser(
+ ComponentName.unflattenFromString("a/a"), userId));
+ assertTrue(service.isComponentEnabledForPackage("a", userId));
+
+ service.onUserStopped(userId);
+
+ assertFalse(service.isComponentEnabledForUser(
+ ComponentName.unflattenFromString("a/a"), userId));
+ assertFalse(service.isComponentEnabledForPackage("a", userId));
+ verify(service).unbindUserServices(eq(userId));
+ }
+
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testUnbindServicesImpl_serviceOfForegroundUser() throws Exception {
+ int switchingUserId = 10;
+ int userId = 99;
+
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ spyOn(service);
+ spyOn(service.mUmInternal);
+ when(service.mUmInternal.isVisibleBackgroundFullUser(userId)).thenReturn(false);
+
+ IInterface iInterface = mock(IInterface.class);
+ when(iInterface.asBinder()).thenReturn(mock(IBinder.class));
+
+ ManagedServices.ManagedServiceInfo serviceInfo = service.new ManagedServiceInfo(
+ iInterface, ComponentName.unflattenFromString("a/a"), userId, false,
+ mock(ServiceConnection.class), 26, 34);
+
+ Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>();
+ removableBoundServices.add(serviceInfo);
+
+ when(service.getRemovableConnectedServices()).thenReturn(removableBoundServices);
+ ArgumentCaptor<SparseArray<Set<ComponentName>>> captor = ArgumentCaptor.forClass(
+ SparseArray.class);
+
+ service.unbindServicesImpl(switchingUserId, true);
+
+ verify(service).unbindFromServices(captor.capture());
+
+ assertEquals(captor.getValue().size(), 1);
+ assertTrue(captor.getValue().indexOfKey(userId) != -1);
+ assertTrue(captor.getValue().get(userId).contains(
+ ComponentName.unflattenFromString("a/a")));
+ }
+
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testUnbindServicesImpl_serviceOfVisibleBackgroundUser() throws Exception {
+ int switchingUserId = 10;
+ int userId = 99;
+
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ spyOn(service);
+ spyOn(service.mUmInternal);
+ when(service.mUmInternal.isVisibleBackgroundFullUser(userId)).thenReturn(true);
+
+ IInterface iInterface = mock(IInterface.class);
+ when(iInterface.asBinder()).thenReturn(mock(IBinder.class));
+
+ ManagedServices.ManagedServiceInfo serviceInfo = service.new ManagedServiceInfo(
+ iInterface, ComponentName.unflattenFromString("a/a"), userId,
+ false, mock(ServiceConnection.class), 26, 34);
+
+ Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>();
+ removableBoundServices.add(serviceInfo);
+
+ when(service.getRemovableConnectedServices()).thenReturn(removableBoundServices);
+ ArgumentCaptor<SparseArray<Set<ComponentName>>> captor = ArgumentCaptor.forClass(
+ SparseArray.class);
+
+ service.unbindServicesImpl(switchingUserId, true);
+
+ verify(service).unbindFromServices(captor.capture());
+
+ assertEquals(captor.getValue().size(), 0);
+ }
+
@Test
public void testOnNullBinding() throws Exception {
Context context = mock(Context.class);
@@ -1681,6 +2051,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
assertFalse(service.isBound(cn, mZero.id));
assertFalse(service.isBound(cn, mTen.id));
}
+
@Test
public void testOnPackagesChanged_nullValuesPassed_noNullPointers() {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
@@ -2012,6 +2383,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isComponentEnabledForCurrentProfiles_isThreadSafe() throws InterruptedException {
for (UserInfo userInfo : mUm.getUsers()) {
mService.addApprovedList("pkg1/cmp1:pkg2/cmp2:pkg3/cmp3", userInfo.id, true);
@@ -2024,6 +2396,20 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isComponentEnabledForUser_isThreadSafe() throws InterruptedException {
+ for (UserInfo userInfo : mUm.getUsers()) {
+ mService.addApprovedList("pkg1/cmp1:pkg2/cmp2:pkg3/cmp3", userInfo.id, true);
+ }
+ testThreadSafety(() -> {
+ mService.rebindServices(false, 0);
+ assertThat(mService.isComponentEnabledForUser(
+ new ComponentName("pkg1", "cmp1"), 0)).isTrue();
+ }, 20, 30);
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isComponentEnabledForCurrentProfiles_profileUserId() {
final int profileUserId = 10;
when(mUserProfiles.isProfileUser(profileUserId, mContext)).thenReturn(true);
@@ -2037,6 +2423,24 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isComponentEnabledForUser_profileUserId() {
+ final int profileUserId = 10;
+ when(mUserProfiles.isProfileUser(profileUserId, mContext)).thenReturn(true);
+ spyOn(mService);
+ doReturn(USER_CURRENT).when(mService).resolveUserId(anyInt());
+
+ // Only approve for parent user (0)
+ mService.addApprovedList("pkg1/cmp1:pkg2/cmp2:pkg3/cmp3", 0, true);
+
+ // Test that the component is enabled after calling rebindServices with profile userId (10)
+ mService.rebindServices(false, profileUserId);
+ assertThat(mService.isComponentEnabledForUser(
+ new ComponentName("pkg1", "cmp1"), profileUserId)).isTrue();
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isComponentEnabledForCurrentProfiles_profileUserId_NAS() {
final int profileUserId = 10;
when(mUserProfiles.isProfileUser(profileUserId, mContext)).thenReturn(true);
@@ -2054,6 +2458,25 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isComponentEnabledForUser_profileUserId_NAS() {
+ final int profileUserId = 10;
+ when(mUserProfiles.isProfileUser(profileUserId, mContext)).thenReturn(true);
+ // Do not rebind for parent users (NAS use-case)
+ ManagedServices service = spy(mService);
+ when(service.allowRebindForParentUser()).thenReturn(false);
+ doReturn(USER_CURRENT).when(service).resolveUserId(anyInt());
+
+ // Only approve for parent user (0)
+ service.addApprovedList("pkg1/cmp1:pkg2/cmp2:pkg3/cmp3", 0, true);
+
+ // Test that the component is disabled after calling rebindServices with profile userId (10)
+ service.rebindServices(false, profileUserId);
+ assertThat(service.isComponentEnabledForUser(
+ new ComponentName("pkg1", "cmp1"), profileUserId)).isFalse();
+ }
+
+ @Test
@EnableFlags(FLAG_LIFETIME_EXTENSION_REFACTOR)
public void testManagedServiceInfoIsSystemUi() {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
@@ -2069,6 +2492,48 @@ public class ManagedServicesTest extends UiServiceTestCase {
assertThat(service0.isSystemUi()).isFalse();
}
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testUserMatchesAndEnabled_profileUser() throws Exception {
+ int currentUserId = 10;
+ int profileUserId = 11;
+
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ ManagedServices.ManagedServiceInfo listener = spy(service.new ManagedServiceInfo(
+ mock(IInterface.class), ComponentName.unflattenFromString("a/a"), currentUserId,
+ false, mock(ServiceConnection.class), 26, 34));
+
+ doReturn(currentUserId).when(service.mUmInternal).getProfileParentId(profileUserId);
+ doReturn(currentUserId).when(service.mUmInternal).getProfileParentId(currentUserId);
+ doReturn(true).when(listener).isEnabledForUser();
+ doReturn(true).when(mUserProfiles).isCurrentProfile(anyInt());
+
+ assertThat(listener.enabledAndUserMatches(profileUserId)).isTrue();
+ }
+
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void testUserMatchesAndDisabled_visibleBackgroudUser() throws Exception {
+ int currentUserId = 10;
+ int profileUserId = 11;
+ int visibleBackgroundUserId = 12;
+
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ ManagedServices.ManagedServiceInfo listener = spy(service.new ManagedServiceInfo(
+ mock(IInterface.class), ComponentName.unflattenFromString("a/a"), profileUserId,
+ false, mock(ServiceConnection.class), 26, 34));
+
+ doReturn(currentUserId).when(service.mUmInternal).getProfileParentId(profileUserId);
+ doReturn(currentUserId).when(service.mUmInternal).getProfileParentId(currentUserId);
+ doReturn(visibleBackgroundUserId).when(service.mUmInternal)
+ .getProfileParentId(visibleBackgroundUserId);
+ doReturn(true).when(listener).isEnabledForUser();
+
+ assertThat(listener.enabledAndUserMatches(visibleBackgroundUserId)).isFalse();
+ }
+
private void mockServiceInfoWithMetaData(List<ComponentName> componentNames,
ManagedServices service, ArrayMap<ComponentName, Bundle> metaDatas)
throws RemoteException {
@@ -2247,26 +2712,47 @@ public class ManagedServicesTest extends UiServiceTestCase {
private void verifyExpectedBoundEntries(ManagedServices service, boolean primary)
throws Exception {
+ verifyExpectedBoundEntries(service, primary, UserHandle.USER_CURRENT);
+ }
+
+ private void verifyExpectedBoundEntries(ManagedServices service, boolean primary,
+ int targetUserId) throws Exception {
ArrayMap<Integer, String> verifyMap = primary ? mExpectedPrimary.get(service.mApprovalLevel)
: mExpectedSecondary.get(service.mApprovalLevel);
for (int userId : verifyMap.keySet()) {
for (String packageOrComponent : verifyMap.get(userId).split(":")) {
if (!TextUtils.isEmpty(packageOrComponent)) {
if (service.mApprovalLevel == APPROVAL_BY_PACKAGE) {
- assertTrue(packageOrComponent,
- service.isComponentEnabledForPackage(packageOrComponent));
+ if (managedServicesConcurrentMultiuser()) {
+ assertTrue(packageOrComponent,
+ service.isComponentEnabledForPackage(packageOrComponent,
+ targetUserId));
+ } else {
+ assertTrue(packageOrComponent,
+ service.isComponentEnabledForPackage(packageOrComponent));
+ }
for (int i = 1; i <= 3; i++) {
ComponentName componentName = ComponentName.unflattenFromString(
packageOrComponent +"/C" + i);
- assertTrue(service.isComponentEnabledForCurrentProfiles(
- componentName));
+ if (managedServicesConcurrentMultiuser()) {
+ assertTrue(service.isComponentEnabledForUser(
+ componentName, targetUserId));
+ } else {
+ assertTrue(service.isComponentEnabledForCurrentProfiles(
+ componentName));
+ }
verify(mIpm, times(1)).getServiceInfo(
eq(componentName), anyLong(), anyInt());
}
} else {
ComponentName componentName =
ComponentName.unflattenFromString(packageOrComponent);
- assertTrue(service.isComponentEnabledForCurrentProfiles(componentName));
+ if (managedServicesConcurrentMultiuser()) {
+ assertTrue(service.isComponentEnabledForUser(componentName,
+ targetUserId));
+ } else {
+ assertTrue(service.isComponentEnabledForCurrentProfiles(componentName));
+ }
verify(mIpm, times(1)).getServiceInfo(
eq(componentName), anyLong(), anyInt());
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 0373eb6e9318..37ab541f12da 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -140,6 +140,7 @@ import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL;
+import static com.android.server.notification.Flags.FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER;
import static com.android.server.notification.Flags.FLAG_REJECT_OLD_NOTIFICATIONS;
import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY;
import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION;
@@ -867,7 +868,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
&& filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
mPackageIntentReceiver = broadcastReceivers.get(i);
}
- if (filter.hasAction(Intent.ACTION_USER_SWITCHED)
+ if (filter.hasAction(Intent.ACTION_USER_STOPPED)
+ || filter.hasAction(Intent.ACTION_USER_SWITCHED)
|| filter.hasAction(Intent.ACTION_PROFILE_UNAVAILABLE)
|| filter.hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
// There may be multiple receivers, get the NMS one
@@ -5383,6 +5385,42 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testGetPackagesWithChannels_blocked() throws Exception {
+ // While we mostly rely on the PreferencesHelper implementation of channels, we filter in
+ // NMS so that we do not return blocked packages.
+ // Three packages; all under user 1.
+ // pkg2 is blocked, but pkg1 and pkg3 are not.
+ String pkg1 = "com.package.one", pkg2 = "com.package.two", pkg3 = "com.package.three";
+ int uid1 = UserHandle.getUid(1, 111);
+ int uid2 = UserHandle.getUid(1, 222);
+ int uid3 = UserHandle.getUid(1, 333);
+
+ when(mPackageManager.getPackageUid(eq(pkg1), anyLong(), anyInt())).thenReturn(uid1);
+ when(mPackageManager.getPackageUid(eq(pkg2), anyLong(), anyInt())).thenReturn(uid2);
+ when(mPackageManager.getPackageUid(eq(pkg3), anyLong(), anyInt())).thenReturn(uid3);
+ when(mPermissionHelper.hasPermission(uid1)).thenReturn(true);
+ when(mPermissionHelper.hasPermission(uid2)).thenReturn(false);
+ when(mPermissionHelper.hasPermission(uid3)).thenReturn(true);
+
+ NotificationChannel channel1 = new NotificationChannel("id1", "name1",
+ NotificationManager.IMPORTANCE_DEFAULT);
+ NotificationChannel channel2 = new NotificationChannel("id3", "name3",
+ NotificationManager.IMPORTANCE_DEFAULT);
+ NotificationChannel channel3 = new NotificationChannel("id4", "name3",
+ NotificationManager.IMPORTANCE_DEFAULT);
+ mService.mPreferencesHelper.createNotificationChannel(pkg1, uid1, channel1, true, false,
+ uid1, false);
+ mService.mPreferencesHelper.createNotificationChannel(pkg2, uid2, channel2, true, false,
+ uid2, false);
+ mService.mPreferencesHelper.createNotificationChannel(pkg3, uid3, channel3, true, false,
+ uid3, false);
+
+ // Output should contain only the package with notification permissions (1, 3).
+ enableInteractAcrossUsers();
+ assertThat(mBinderService.getPackagesWithAnyChannels(1)).containsExactly(pkg1, pkg3);
+ }
+
+ @Test
public void testHasCompanionDevice_failure() throws Exception {
when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
new IllegalArgumentException());
@@ -10992,7 +11030,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners() throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
mService.setCallerIsNormalPackage();
@@ -11010,20 +11047,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void testAddAutomaticZenRule_typeManagedCanBeUsedBySystem() throws Exception {
addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_MANAGED);
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps() throws Exception {
addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps(
AutomaticZenRule.TYPE_MANAGED);
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing() throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
mService.setCallerIsNormalPackage();
@@ -11046,7 +11080,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem() throws Exception {
reset(mPackageManagerInternal);
when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
@@ -11054,7 +11087,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps() throws Exception {
reset(mPackageManagerInternal);
when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true);
@@ -11097,7 +11129,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void addAutomaticZenRule_fromUser_mappedToOriginUser() throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
mService.isSystemUid = true;
@@ -11109,7 +11140,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem() throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
mService.isSystemUid = true;
@@ -11121,7 +11151,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void addAutomaticZenRule_fromApp_mappedToOriginApp() throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
mService.setCallerIsNormalPackage();
@@ -11133,7 +11162,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void addAutomaticZenRule_fromAppFromUser_blocked() throws Exception {
setUpMockZenTest();
mService.setCallerIsNormalPackage();
@@ -11143,7 +11171,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void updateAutomaticZenRule_fromUserFromSystem_allowed() throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
mService.isSystemUid = true;
@@ -11155,7 +11182,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void updateAutomaticZenRule_fromUserFromApp_blocked() throws Exception {
setUpMockZenTest();
mService.setCallerIsNormalPackage();
@@ -11165,7 +11191,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void removeAutomaticZenRule_fromUserFromSystem_allowed() throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
mService.isSystemUid = true;
@@ -11177,7 +11202,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void removeAutomaticZenRule_fromUserFromApp_blocked() throws Exception {
setUpMockZenTest();
mService.setCallerIsNormalPackage();
@@ -11187,7 +11211,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void setAutomaticZenRuleState_fromAppWithConditionFromUser_originUserInApp()
throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
@@ -11202,7 +11225,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void setAutomaticZenRuleState_fromAppWithConditionNotFromUser_originApp()
throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
@@ -11217,7 +11239,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void setAutomaticZenRuleState_fromSystemWithConditionFromUser_originUserInSystemUi()
throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
@@ -11231,7 +11252,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyInt());
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_originSystem()
throws Exception {
ZenModeHelper zenModeHelper = setUpMockZenTest();
@@ -11402,7 +11422,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception {
mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged(
mUserId, "rule.owner.pkg", "rule_id", AUTOMATIC_RULE_STATUS_ACTIVATED));
@@ -16266,7 +16285,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
- inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd();
+ inOrder.verify(mPreferencesHelper).syncHasPriorityChannels();
inOrder.verifyNoMoreInteractions();
}
@@ -16282,11 +16301,25 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
- inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd();
+ inOrder.verify(mPreferencesHelper).syncHasPriorityChannels();
inOrder.verifyNoMoreInteractions();
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void onUserStopped_callBackToListeners() {
+ Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, 20);
+
+ mUserIntentReceiver.onReceive(mContext, intent);
+
+ verify(mConditionProviders).onUserStopped(eq(20));
+ verify(mListeners).onUserStopped(eq(20));
+ verify(mAssistants).onUserStopped(eq(20));
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isNotificationPolicyAccessGranted_invalidPackage() throws Exception {
final String notReal = "NOT REAL";
final var checker = mService.permissionChecker;
@@ -16303,6 +16336,25 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isNotificationPolicyAccessGranted_invalidPackage_concurrent_multiUser()
+ throws Exception {
+ final String notReal = "NOT REAL";
+ final var checker = mService.permissionChecker;
+
+ when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow(
+ PackageManager.NameNotFoundException.class);
+
+ assertThat(mBinderService.isNotificationPolicyAccessGranted(notReal)).isFalse();
+ verify(mPackageManagerClient).getPackageUidAsUser(eq(notReal), anyInt());
+ verify(checker, never()).check(any(), anyInt(), anyInt(), anyBoolean());
+ verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(notReal), anyInt());
+ verify(mListeners, never()).isComponentEnabledForPackage(any(), anyInt());
+ verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isNotificationPolicyAccessGranted_hasPermission() throws Exception {
final String packageName = "target";
final int uid = 123;
@@ -16321,6 +16373,27 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isNotificationPolicyAccessGranted_hasPermission_concurrent_multiUser()
+ throws Exception {
+ final String packageName = "target";
+ final int uid = 123;
+ final var checker = mService.permissionChecker;
+
+ when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
+ when(checker.check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
+ verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
+ verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
+ verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(packageName), anyInt());
+ verify(mListeners, never()).isComponentEnabledForPackage(any(), anyInt());
+ verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isNotificationPolicyAccessGranted_isPackageAllowed() throws Exception {
final String packageName = "target";
final int uid = 123;
@@ -16339,6 +16412,27 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isNotificationPolicyAccessGranted_isPackageAllowed_concurrent_multiUser()
+ throws Exception {
+ final String packageName = "target";
+ final int uid = 123;
+ final var checker = mService.permissionChecker;
+
+ when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
+ when(mConditionProviders.isPackageOrComponentAllowed(eq(packageName), anyInt()))
+ .thenReturn(true);
+
+ assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
+ verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
+ verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
+ verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
+ verify(mListeners, never()).isComponentEnabledForPackage(any(), anyInt());
+ verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isNotificationPolicyAccessGranted_isComponentEnabled() throws Exception {
final String packageName = "target";
final int uid = 123;
@@ -16356,6 +16450,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isNotificationPolicyAccessGranted_isComponentEnabled_concurrent_multiUser()
+ throws Exception {
+ final String packageName = "target";
+ final int uid = 123;
+ final var checker = mService.permissionChecker;
+
+ when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
+ when(mListeners.isComponentEnabledForPackage(packageName, mUserId)).thenReturn(true);
+
+ assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
+ verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
+ verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
+ verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
+ verify(mListeners).isComponentEnabledForPackage(packageName, mUserId);
+ verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt());
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isNotificationPolicyAccessGranted_isDeviceOwner() throws Exception {
final String packageName = "target";
final int uid = 123;
@@ -16372,10 +16486,30 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
}
+ @Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isNotificationPolicyAccessGranted_isDeviceOwner_concurrent_multiUser()
+ throws Exception {
+ final String packageName = "target";
+ final int uid = 123;
+ final var checker = mService.permissionChecker;
+
+ when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
+ when(mDevicePolicyManager.isActiveDeviceOwner(uid)).thenReturn(true);
+
+ assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue();
+ verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
+ verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
+ verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
+ verify(mListeners).isComponentEnabledForPackage(packageName, mUserId);
+ verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
+ }
+
/**
* b/292163859
*/
@Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isNotificationPolicyAccessGranted_callerIsDeviceOwner() throws Exception {
final String packageName = "target";
final int uid = 123;
@@ -16394,7 +16528,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid);
}
+ /**
+ * b/292163859
+ */
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isNotificationPolicyAccessGranted_callerIsDeviceOwner_concurrent_multiUser()
+ throws Exception {
+ final String packageName = "target";
+ final int uid = 123;
+ final int callingUid = Binder.getCallingUid();
+ final var checker = mService.permissionChecker;
+
+ when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
+ when(mDevicePolicyManager.isActiveDeviceOwner(callingUid)).thenReturn(true);
+
+ assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
+ verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
+ verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
+ verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
+ verify(mListeners).isComponentEnabledForPackage(packageName, mUserId);
+ verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
+ verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid);
+ }
+
+ @Test
+ @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
public void isNotificationPolicyAccessGranted_notGranted() throws Exception {
final String packageName = "target";
final int uid = 123;
@@ -16411,6 +16570,24 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER)
+ public void isNotificationPolicyAccessGranted_notGranted_concurrent_multiUser()
+ throws Exception {
+ final String packageName = "target";
+ final int uid = 123;
+ final var checker = mService.permissionChecker;
+
+ when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
+
+ assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse();
+ verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt());
+ verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true);
+ verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt());
+ verify(mListeners).isComponentEnabledForPackage(packageName, mUserId);
+ verify(mDevicePolicyManager).isActiveDeviceOwner(uid);
+ }
+
+ @Test
public void testResetDefaultDnd() {
TestableNotificationManagerService service = spy(mService);
UserInfo user = new UserInfo(0, "owner", 0);
@@ -16445,7 +16622,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void setDeviceEffectsApplier_succeeds() throws Exception {
initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
@@ -16456,7 +16632,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void setDeviceEffectsApplier_tooLate_throws() throws Exception {
initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
@@ -16465,7 +16640,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
public void setDeviceEffectsApplier_calledTwice_throws() throws Exception {
initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
@@ -16477,7 +16651,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mService.setCallerIsNormalPackage();
ZenModeHelper zenHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = zenHelper;
@@ -16494,7 +16667,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void setNotificationPolicy_systemCaller_setsGlobalPolicy() throws RemoteException {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = zenModeHelper;
when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
@@ -16534,7 +16706,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private void setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy(
@AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
throws RemoteException {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mService.setCallerIsNormalPackage();
ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = zenModeHelper;
@@ -16561,7 +16732,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void setNotificationPolicy_withoutCompat_setsGlobalPolicy() throws RemoteException {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mService.setCallerIsNormalPackage();
ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = zenModeHelper;
@@ -16577,7 +16747,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void getNotificationPolicy_mappedFromImplicitRule() throws RemoteException {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mService.setCallerIsNormalPackage();
ZenModeHelper zenHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = zenHelper;
@@ -16592,7 +16761,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void setInterruptionFilter_mappedToImplicitRule() throws RemoteException {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mService.setCallerIsNormalPackage();
ZenModeHelper zenHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = zenHelper;
@@ -16608,7 +16776,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void setInterruptionFilter_systemCaller_setsGlobalPolicy() throws RemoteException {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mService.setCallerIsNormalPackage();
ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = zenModeHelper;
@@ -16647,7 +16814,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private void setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen(
@AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy)
throws RemoteException {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = zenModeHelper;
mService.setCallerIsNormalPackage();
@@ -16672,7 +16838,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void requestInterruptionFilterFromListener_fromApp_doesNotSetGlobalZen()
throws Exception {
@@ -16690,7 +16855,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void requestInterruptionFilterFromListener_fromSystem_setsGlobalZen()
throws Exception {
@@ -16709,24 +16873,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @DisableFlags(android.app.Flags.FLAG_MODES_API)
- public void requestInterruptionFilterFromListener_flagOff_callsRequestFromListener()
- throws Exception {
- mService.setCallerIsNormalPackage();
- mService.mZenModeHelper = mock(ZenModeHelper.class);
- ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
- when(mListeners.checkServiceTokenLocked(any())).thenReturn(info);
- info.component = new ComponentName("pkg", "cls");
-
- mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class),
- INTERRUPTION_FILTER_PRIORITY);
-
- verify(mService.mZenModeHelper).requestFromListener(eq(info.component),
- eq(INTERRUPTION_FILTER_PRIORITY), eq(mUid), /* fromSystemOrSystemUi= */ eq(false));
- }
-
- @Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception {
setUpRealZenTest();
@@ -16752,7 +16898,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception {
setUpRealZenTest();
@@ -16778,7 +16923,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({android.app.Flags.FLAG_MODES_API, android.app.Flags.FLAG_MODES_UI})
+ @EnableFlags(android.app.Flags.FLAG_MODES_UI)
public void setNotificationPolicy_fromSystemApp_appliesPriorityChannelsAllowed()
throws Exception {
setUpRealZenTest();
@@ -16808,7 +16953,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({android.app.Flags.FLAG_MODES_API, android.app.Flags.FLAG_MODES_UI})
+ @EnableFlags(android.app.Flags.FLAG_MODES_UI)
@DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void setNotificationPolicy_fromRegularAppThatCanModifyPolicy_ignoresState()
throws Exception {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 3f26cd9258af..5dea44d6ebf4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -363,7 +363,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
.when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
- NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
+ NotificationManager.Policy.STATE_HAS_PRIORITY_CHANNELS, 0);
when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(),
anyString(), eq(null), anyString())).thenReturn(MODE_DEFAULT);
@@ -2733,7 +2733,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
uid, false);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
} else {
@@ -2748,7 +2748,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setBypassDnd(true);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
uid, false);
- assertTrue(mHelper.areChannelsBypassingDnd());
+ assertTrue(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(true));
@@ -2760,7 +2760,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// delete channels
mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false);
- assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
+ assertTrue(mHelper.hasPriorityChannels()); // channel2 can still bypass DND
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
} else {
@@ -2770,7 +2770,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
resetZenModeHelper();
mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(false));
@@ -2792,7 +2792,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
uid, false);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
} else {
@@ -2807,7 +2807,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.createNotificationChannel(PKG_N_MR1, uid, update, true, true,
uid, false);
- assertTrue(mHelper.areChannelsBypassingDnd());
+ assertTrue(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(true));
@@ -2829,7 +2829,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
uid, false);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
} else {
@@ -2844,7 +2844,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setBypassDnd(true);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
uid, false);
- assertTrue(mHelper.areChannelsBypassingDnd());
+ assertTrue(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(true));
@@ -2856,7 +2856,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// delete channels
mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false);
- assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
+ assertTrue(mHelper.hasPriorityChannels()); // channel2 can still bypass DND
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
} else {
@@ -2866,7 +2866,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
resetZenModeHelper();
mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(false));
@@ -2884,9 +2884,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// start in a 'allowed to bypass dnd state'
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
- NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
+ NotificationManager.Policy.STATE_HAS_PRIORITY_CHANNELS, 0);
when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
- mHelper.syncChannelsBypassingDnd();
+ mHelper.syncHasPriorityChannels();
// create notification channel that can bypass dnd, but app is blocked
// expected result: areChannelsBypassingDnd = false
@@ -2899,7 +2899,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setBypassDnd(true);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
uid, false);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(false));
@@ -2917,9 +2917,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// start in a 'allowed to bypass dnd state'
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
- NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
+ NotificationManager.Policy.STATE_HAS_PRIORITY_CHANNELS, 0);
when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
- mHelper.syncChannelsBypassingDnd();
+ mHelper.syncHasPriorityChannels();
// create notification channel that can bypass dnd, but app is blocked
// expected result: areChannelsBypassingDnd = false
@@ -2927,7 +2927,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setBypassDnd(true);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
uid, false);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(false));
@@ -2945,9 +2945,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// start in a 'allowed to bypass dnd state'
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
- NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
+ NotificationManager.Policy.STATE_HAS_PRIORITY_CHANNELS, 0);
when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
- mHelper.syncChannelsBypassingDnd();
+ mHelper.syncHasPriorityChannels();
// create notification channel that can bypass dnd, but app is blocked
// expected result: areChannelsBypassingDnd = false
@@ -2955,7 +2955,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setBypassDnd(true);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true,
uid, false);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(false));
@@ -2977,7 +2977,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false,
uid, false);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
} else {
@@ -2990,7 +2990,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// expected result: areChannelsBypassingDnd = true
channel.setBypassDnd(true);
mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true);
- assertTrue(mHelper.areChannelsBypassingDnd());
+ assertTrue(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(true));
@@ -3004,7 +3004,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// expected result: areChannelsBypassingDnd = false
channel.setBypassDnd(false);
mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(false));
@@ -3020,10 +3020,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// start notification policy off with mAreChannelsBypassingDnd = true, but
// RankingHelper should change to false
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
- NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
+ NotificationManager.Policy.STATE_HAS_PRIORITY_CHANNELS, 0);
when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
- mHelper.syncChannelsBypassingDnd();
- assertFalse(mHelper.areChannelsBypassingDnd());
+ mHelper.syncHasPriorityChannels();
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, times(1)).updateHasPriorityChannels(eq(UserHandle.CURRENT),
eq(false));
@@ -3039,7 +3039,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// start notification policy off with mAreChannelsBypassingDnd = false
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0);
when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
- assertFalse(mHelper.areChannelsBypassingDnd());
+ assertFalse(mHelper.hasPriorityChannels());
if (android.app.Flags.modesUi()) {
verify(mMockZenModeHelper, never()).updateHasPriorityChannels(any(), anyBoolean());
} else {
@@ -3050,7 +3050,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void syncChannelsBypassingDnd_includesProfilesOfCurrentUser() throws Exception {
+ public void syncHasPriorityChannels_includesProfilesOfCurrentUser() throws Exception {
when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0, 10}));
when(mPermissionHelper.hasPermission(anyInt())).thenReturn(true);
ApplicationInfo appInfo = new ApplicationInfo();
@@ -3067,13 +3067,13 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.createNotificationChannel("com.example", UserHandle.getUid(10, 444), withBypass,
false, false, Process.SYSTEM_UID, true);
- mHelper.syncChannelsBypassingDnd();
+ mHelper.syncHasPriorityChannels();
- assertThat(mHelper.areChannelsBypassingDnd()).isTrue();
+ assertThat(mHelper.hasPriorityChannels()).isTrue();
}
@Test
- public void syncChannelsBypassingDnd_excludesOtherUsers() throws Exception {
+ public void syncHasPriorityChannels_excludesOtherUsers() throws Exception {
when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0}));
when(mPermissionHelper.hasPermission(anyInt())).thenReturn(true);
ApplicationInfo appInfo = new ApplicationInfo();
@@ -3090,9 +3090,70 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.createNotificationChannel("com.example", UserHandle.getUid(10, 444), withBypass,
false, false, Process.SYSTEM_UID, true);
- mHelper.syncChannelsBypassingDnd();
+ mHelper.syncHasPriorityChannels();
- assertThat(mHelper.areChannelsBypassingDnd()).isFalse();
+ assertThat(mHelper.hasPriorityChannels()).isFalse();
+ }
+
+ @Test
+ public void getPackagesWithAnyChannels_noChannels() {
+ assertThat(mHelper.getPackagesWithAnyChannels(UserHandle.getUserId(UID_O))).isEmpty();
+ }
+
+ @Test
+ public void getPackagesWithAnyChannels_someChannels() {
+ // 2 channels under PKG_N_MR1, 1 under PKG_O
+ NotificationChannel channel1 = new NotificationChannel("1", "something",
+ IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, UID_N_MR1,
+ false);
+ NotificationChannel channel2 = new NotificationChannel("2", "another", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, UID_N_MR1,
+ false);
+
+ NotificationChannel other = new NotificationChannel("3", "still another",
+ IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, other, true, false, UID_O, false);
+
+ assertThat(mHelper.getPackagesWithAnyChannels(USER.getIdentifier())).containsExactly(
+ PKG_N_MR1, PKG_O);
+ }
+
+ @Test
+ public void getPackagesWithAnyChannels_onlyDeleted() {
+ NotificationChannel channel1 = new NotificationChannel("1", "something",
+ IMPORTANCE_DEFAULT);
+ channel1.setDeleted(true);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel1, true, false, UID_O,
+ false);
+ NotificationChannel channel2 = new NotificationChannel("2", "another", IMPORTANCE_DEFAULT);
+ channel2.setDeleted(true);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O,
+ false);
+
+ assertThat(mHelper.getPackagesWithAnyChannels(UserHandle.getUserId(UID_O))).isEmpty();
+ }
+
+ @Test
+ public void getPackagesWithAnyChannels_distinguishesUsers() throws Exception {
+ // Set a package up for both users 0 and 10
+ String pkgName = "test.package";
+ int uid0 = UserHandle.getUid(0, 1234);
+ int uid10 = UserHandle.getUid(10, 1234);
+ setUpPackageWithUid(pkgName, uid0);
+ setUpPackageWithUid(pkgName, uid10);
+
+ // but only user 10 has channels
+ NotificationChannel channel1 = new NotificationChannel("1", "something",
+ IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(pkgName, uid10, channel1, true, false, uid10,
+ false);
+ NotificationChannel channel2 = new NotificationChannel("2", "another", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(pkgName, uid10, channel2, true, false, uid10,
+ false);
+
+ assertThat(mHelper.getPackagesWithAnyChannels(0)).isEmpty();
+ assertThat(mHelper.getPackagesWithAnyChannels(10)).containsExactly(pkgName);
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index f90034614383..ec428d506e7b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -17,9 +17,10 @@ package com.android.server.notification;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_LOW;
-
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.TestCase.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -29,7 +30,6 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.app.Flags;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -40,7 +40,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
-import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
@@ -67,7 +66,6 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -154,7 +152,7 @@ public class RankingHelperTest extends UiServiceTestCase {
.thenReturn(SOUND_URI);
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
- NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
+ NotificationManager.Policy.STATE_HAS_PRIORITY_CHANNELS, 0);
when(mMockZenModeHelper.getNotificationPolicy(any())).thenReturn(mTestNotificationPolicy);
mHelper = new RankingHelper(getContext(), mHandler, mConfig, mMockZenModeHelper,
mUsageStats, new String[] {ImportanceExtractor.class.getName()},
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
index 75552bc433c5..f3813437a9c5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
@@ -20,10 +20,7 @@ import static android.service.notification.ZenAdapters.notificationPolicyToZenPo
import static com.google.common.truth.Truth.assertThat;
-import android.app.Flags;
import android.app.NotificationManager.Policy;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenPolicy;
@@ -137,8 +134,7 @@ public class ZenAdaptersTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
- public void notificationPolicyToZenPolicy_modesApi_priorityChannels() {
+ public void notificationPolicyToZenPolicy_priorityChannels() {
Policy policy = new Policy(0, 0, 0, 0,
Policy.policyState(false, true), 0);
@@ -151,20 +147,4 @@ public class ZenAdaptersTest extends UiServiceTestCase {
assertThat(zenPolicyNotAllowed.getPriorityChannelsAllowed()).isEqualTo(
ZenPolicy.STATE_DISALLOW);
}
-
- @Test
- @DisableFlags(Flags.FLAG_MODES_API)
- public void notificationPolicyToZenPolicy_noModesApi_priorityChannelsUnset() {
- Policy policy = new Policy(0, 0, 0, 0,
- Policy.policyState(false, true), 0);
-
- ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
- assertThat(zenPolicy.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_UNSET);
-
- Policy notAllowed = new Policy(0, 0, 0, 0,
- Policy.policyState(false, false), 0);
- ZenPolicy zenPolicyNotAllowed = notificationPolicyToZenPolicy(notAllowed);
- assertThat(zenPolicyNotAllowed.getPriorityChannelsAllowed()).isEqualTo(
- ZenPolicy.STATE_UNSET);
- }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java
index af911e811e5e..9a2b748a9bcc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java
@@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
-import android.app.Flags;
import android.os.Parcel;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenDeviceEffects;
@@ -31,7 +30,6 @@ import com.android.server.UiServiceTestCase;
import com.google.common.collect.ImmutableSet;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,11 +40,6 @@ public class ZenDeviceEffectsTest extends UiServiceTestCase {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
- @Before
- public final void setUp() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
- }
-
@Test
public void builder() {
ZenDeviceEffects deviceEffects =
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index b42a6a5a7382..67efb9e76692 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -174,7 +174,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
}
assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
- config.areChannelsBypassingDnd = true;
+ config.hasPriorityChannels = true;
assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
if (Flags.modesUi()) {
@@ -187,7 +187,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
- config.areChannelsBypassingDnd = false;
+ config.hasPriorityChannels = false;
if (Flags.modesUi()) {
config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
.allowPriorityChannels(false)
@@ -417,7 +417,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
assertTrue(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
- config.areChannelsBypassingDnd = true;
+ config.hasPriorityChannels = true;
if (Flags.modesUi()) {
config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
.allowPriorityChannels(true)
@@ -429,7 +429,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
assertFalse(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
- config.areChannelsBypassingDnd = false;
+ config.hasPriorityChannels = false;
if (Flags.modesUi()) {
config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
.allowPriorityChannels(false)
@@ -488,33 +488,33 @@ public class ZenModeConfigTest extends UiServiceTestCase {
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.zenPolicy = null;
rule.zenDeviceEffects = null;
- assertThat(rule.canBeUpdatedByApp()).isTrue();
+ assertThat(rule.isUserModified()).isFalse();
rule.userModifiedFields = 1;
- assertThat(rule.canBeUpdatedByApp()).isFalse();
+ assertThat(rule.isUserModified()).isTrue();
}
@Test
public void testCanBeUpdatedByApp_policyModified() throws Exception {
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.zenPolicy = new ZenPolicy();
- assertThat(rule.canBeUpdatedByApp()).isTrue();
+ assertThat(rule.isUserModified()).isFalse();
rule.zenPolicyUserModifiedFields = 1;
- assertThat(rule.canBeUpdatedByApp()).isFalse();
+ assertThat(rule.isUserModified()).isTrue();
}
@Test
public void testCanBeUpdatedByApp_deviceEffectsModified() throws Exception {
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.zenDeviceEffects = new ZenDeviceEffects.Builder().build();
- assertThat(rule.canBeUpdatedByApp()).isTrue();
+ assertThat(rule.isUserModified()).isFalse();
rule.zenDeviceEffectsUserModifiedFields = 1;
- assertThat(rule.canBeUpdatedByApp()).isFalse();
+ assertThat(rule.isUserModified()).isTrue();
}
@Test
@@ -548,7 +548,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.creationTime = 123;
rule.id = "id";
rule.zenMode = INTERRUPTION_FILTER;
- rule.modified = true;
rule.name = NAME;
rule.setConditionOverride(OVERRIDE_DEACTIVATE);
rule.pkg = OWNER.getPackageName();
@@ -564,6 +563,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.deletionInstant = Instant.ofEpochMilli(1701790147000L);
if (Flags.modesUi()) {
rule.disabledOrigin = ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI;
+ if (Flags.modesCleanupImplicit()) {
+ rule.lastActivation = Instant.ofEpochMilli(456);
+ }
}
config.automaticRules.put(rule.id, rule);
@@ -585,7 +587,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(rule.condition, ruleActual.condition);
assertEquals(rule.enabled, ruleActual.enabled);
assertEquals(rule.creationTime, ruleActual.creationTime);
- assertEquals(rule.modified, ruleActual.modified);
assertEquals(rule.conditionId, ruleActual.conditionId);
assertEquals(rule.name, ruleActual.name);
assertEquals(rule.zenMode, ruleActual.zenMode);
@@ -602,6 +603,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(rule.deletionInstant, ruleActual.deletionInstant);
if (Flags.modesUi()) {
assertEquals(rule.disabledOrigin, ruleActual.disabledOrigin);
+ if (Flags.modesCleanupImplicit()) {
+ assertEquals(rule.lastActivation, ruleActual.lastActivation);
+ }
}
if (Flags.backupRestoreLogging()) {
verify(logger).logItemsBackedUp(DATA_TYPE_ZEN_RULES, 2);
@@ -620,7 +624,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.creationTime = 123;
rule.id = "id";
rule.zenMode = INTERRUPTION_FILTER;
- rule.modified = true;
rule.name = NAME;
rule.setConditionOverride(OVERRIDE_DEACTIVATE);
rule.pkg = OWNER.getPackageName();
@@ -636,6 +639,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.deletionInstant = Instant.ofEpochMilli(1701790147000L);
if (Flags.modesUi()) {
rule.disabledOrigin = ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI;
+ if (Flags.modesCleanupImplicit()) {
+ rule.lastActivation = Instant.ofEpochMilli(789);
+ }
}
Parcel parcel = Parcel.obtain();
@@ -651,7 +657,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(rule.condition, parceled.condition);
assertEquals(rule.enabled, parceled.enabled);
assertEquals(rule.creationTime, parceled.creationTime);
- assertEquals(rule.modified, parceled.modified);
assertEquals(rule.conditionId, parceled.conditionId);
assertEquals(rule.name, parceled.name);
assertEquals(rule.zenMode, parceled.zenMode);
@@ -668,6 +673,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(rule.deletionInstant, parceled.deletionInstant);
if (Flags.modesUi()) {
assertEquals(rule.disabledOrigin, parceled.disabledOrigin);
+ if (Flags.modesCleanupImplicit()) {
+ assertEquals(rule.lastActivation, parceled.lastActivation);
+ }
}
assertEquals(rule, parceled);
@@ -685,7 +693,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.creationTime = 123;
rule.id = "id";
rule.zenMode = Settings.Global.ZEN_MODE_ALARMS;
- rule.modified = true;
rule.name = "name";
rule.snoozing = true;
rule.pkg = "b";
@@ -705,7 +712,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(rule.condition, fromXml.condition);
assertEquals(rule.enabled, fromXml.enabled);
assertEquals(rule.creationTime, fromXml.creationTime);
- assertEquals(rule.modified, fromXml.modified);
assertEquals(rule.conditionId, fromXml.conditionId);
assertEquals(rule.name, fromXml.name);
assertEquals(rule.zenMode, fromXml.zenMode);
@@ -721,7 +727,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.enabled = ENABLED;
rule.id = "id";
rule.zenMode = INTERRUPTION_FILTER;
- rule.modified = true;
rule.name = NAME;
rule.setConditionOverride(OVERRIDE_DEACTIVATE);
rule.pkg = OWNER.getPackageName();
@@ -753,6 +758,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.deletionInstant = Instant.ofEpochMilli(1701790147000L);
if (Flags.modesUi()) {
rule.disabledOrigin = ZenModeConfig.ORIGIN_APP;
+ if (Flags.modesCleanupImplicit()) {
+ rule.lastActivation = Instant.ofEpochMilli(123);
+ }
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -770,7 +778,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(rule.condition, fromXml.condition);
assertEquals(rule.enabled, fromXml.enabled);
assertEquals(rule.creationTime, fromXml.creationTime);
- assertEquals(rule.modified, fromXml.modified);
assertEquals(rule.conditionId, fromXml.conditionId);
assertEquals(rule.name, fromXml.name);
assertEquals(rule.zenMode, fromXml.zenMode);
@@ -789,6 +796,9 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(rule.deletionInstant, fromXml.deletionInstant);
if (Flags.modesUi()) {
assertEquals(rule.disabledOrigin, fromXml.disabledOrigin);
+ if (Flags.modesCleanupImplicit()) {
+ assertEquals(rule.lastActivation, fromXml.lastActivation);
+ }
}
}
@@ -916,7 +926,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.userModifiedFields |= AutomaticZenRule.FIELD_NAME;
assertThat(rule.userModifiedFields).isEqualTo(1);
- assertThat(rule.canBeUpdatedByApp()).isFalse();
+ assertThat(rule.isUserModified()).isTrue();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
writeRuleXml(rule, baos);
@@ -924,7 +934,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
ZenModeConfig.ZenRule fromXml = readRuleXml(bais);
assertThat(fromXml.userModifiedFields).isEqualTo(rule.userModifiedFields);
- assertThat(fromXml.canBeUpdatedByApp()).isFalse();
+ assertThat(fromXml.isUserModified()).isTrue();
}
@Test
@@ -1259,7 +1269,6 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.creationTime = 123;
rule.id = "id";
rule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- rule.modified = true;
rule.name = "name";
rule.pkg = "b";
config.automaticRules.put("key", rule);
@@ -1348,7 +1357,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
config.setSuppressedVisualEffects(0);
config.setAllowPriorityChannels(false);
}
- config.areChannelsBypassingDnd = false;
+ config.hasPriorityChannels = false;
return config;
}
@@ -1383,7 +1392,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
config.setSuppressedVisualEffects(0);
config.setAllowPriorityChannels(true);
}
- config.areChannelsBypassingDnd = false;
+ config.hasPriorityChannels = false;
return config;
}
@@ -1410,7 +1419,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
config.setAllowConversationsFrom(CONVERSATION_SENDERS_NONE);
config.setSuppressedVisualEffects(0);
}
- config.areChannelsBypassingDnd = false;
+ config.hasPriorityChannels = false;
return config;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
index b138c72875a6..6d0bf8b322fd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
@@ -16,7 +16,6 @@
package com.android.server.notification;
-import static android.app.Flags.FLAG_MODES_API;
import static android.app.Flags.FLAG_MODES_UI;
import static com.google.common.truth.Truth.assertThat;
@@ -64,7 +63,6 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
@@ -78,20 +76,14 @@ public class ZenModeDiffTest extends UiServiceTestCase {
// version is not included in the diff; manual & automatic rules have special handling;
// deleted rules are not included in the diff.
public static final Set<String> ZEN_MODE_CONFIG_EXEMPT_FIELDS =
- android.app.Flags.modesApi()
- ? Set.of("version", "manualRule", "automaticRules", "deletedRules")
- : Set.of("version", "manualRule", "automaticRules");
-
- // allowPriorityChannels is flagged by android.app.modes_api
- public static final Set<String> ZEN_MODE_CONFIG_FLAGGED_FIELDS =
- Set.of("allowPriorityChannels");
+ Set.of("version", "manualRule", "automaticRules", "deletedRules");
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Parameters(name = "{0}")
public static List<FlagsParameterization> getParams() {
- return FlagsParameterization.progressionOf(FLAG_MODES_API, FLAG_MODES_UI);
+ return FlagsParameterization.progressionOf(FLAG_MODES_UI);
}
public ZenModeDiffTest(FlagsParameterization flags) {
@@ -147,7 +139,7 @@ public class ZenModeDiffTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void testRuleDiff_toStringNoChangeAddRemove() throws Exception {
// Start with two identical rules
ZenModeConfig.ZenRule r1 = makeRule();
@@ -164,7 +156,7 @@ public class ZenModeDiffTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void testRuleDiff_toString() throws Exception {
// Start with two identical rules
ZenModeConfig.ZenRule r1 = makeRule();
@@ -218,7 +210,6 @@ public class ZenModeDiffTest extends UiServiceTestCase {
+ "mPriorityCalls:2->1, "
+ "mConversationSenders:2->1, "
+ "mAllowChannels:2->1}, "
- + "modified:true->false, "
+ "pkg:string1->string2, "
+ "zenDeviceEffects:ZenDeviceEffectsDiff{"
+ "mGrayscale:true->false, "
@@ -241,7 +232,7 @@ public class ZenModeDiffTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void testRuleDiff_toStringNullStartPolicy() throws Exception {
// Start with two identical rules
ZenModeConfig.ZenRule r1 = makeRule();
@@ -278,7 +269,6 @@ public class ZenModeDiffTest extends UiServiceTestCase {
+ "creationTime:200->100, "
+ "enabler:string1->string2, "
+ "zenPolicy:ZenPolicyDiff{added}, "
- + "modified:true->false, "
+ "pkg:string1->string2, "
+ "zenDeviceEffects:ZenDeviceEffectsDiff{added}, "
+ "triggerDescription:string1->string2, "
@@ -485,16 +475,10 @@ public class ZenModeDiffTest extends UiServiceTestCase {
// "Metadata" fields are never compared.
Set<String> exemptFields = new LinkedHashSet<>(
Set.of("userModifiedFields", "zenPolicyUserModifiedFields",
- "zenDeviceEffectsUserModifiedFields", "deletionInstant", "disabledOrigin"));
+ "zenDeviceEffectsUserModifiedFields", "deletionInstant", "disabledOrigin",
+ "lastActivation"));
// Flagged fields are only compared if their flag is on.
- if (!Flags.modesApi()) {
- exemptFields.addAll(
- Set.of(RuleDiff.FIELD_TYPE, RuleDiff.FIELD_TRIGGER_DESCRIPTION,
- RuleDiff.FIELD_ICON_RES, RuleDiff.FIELD_ALLOW_MANUAL,
- RuleDiff.FIELD_ZEN_DEVICE_EFFECTS,
- RuleDiff.FIELD_LEGACY_SUPPRESSED_EFFECTS));
- }
- if (Flags.modesApi() && Flags.modesUi()) {
+ if (Flags.modesUi()) {
exemptFields.add(RuleDiff.FIELD_SNOOZING); // Obsolete.
} else {
exemptFields.add(RuleDiff.FIELD_CONDITION_OVERRIDE);
@@ -530,35 +514,6 @@ public class ZenModeDiffTest extends UiServiceTestCase {
ArrayMap<String, Object> expectedFrom = new ArrayMap<>();
ArrayMap<String, Object> expectedTo = new ArrayMap<>();
List<Field> fieldsForDiff = getFieldsForDiffCheck(
- ZenModeConfig.class, getConfigExemptAndFlaggedFields(), false);
- generateFieldDiffs(c1, c2, fieldsForDiff, expectedFrom, expectedTo);
-
- ZenModeDiff.ConfigDiff d = new ZenModeDiff.ConfigDiff(c1, c2);
- assertTrue(d.hasDiff());
-
- // Now diff them and check that each of the fields has a diff
- for (Field f : fieldsForDiff) {
- String name = f.getName();
- assertNotNull("diff not found for field: " + name, d.getDiffForField(name));
- assertTrue(d.getDiffForField(name).hasDiff());
- assertTrue("unexpected field: " + name, expectedFrom.containsKey(name));
- assertTrue("unexpected field: " + name, expectedTo.containsKey(name));
- assertEquals(expectedFrom.get(name), d.getDiffForField(name).from());
- assertEquals(expectedTo.get(name), d.getDiffForField(name).to());
- }
- }
-
- @Test
- @EnableFlags(FLAG_MODES_API)
- public void testConfigDiff_fieldDiffs_flagOn() throws Exception {
- // these two start the same
- ZenModeConfig c1 = new ZenModeConfig();
- ZenModeConfig c2 = new ZenModeConfig();
-
- // maps mapping field name -> expected output value as we set diffs
- ArrayMap<String, Object> expectedFrom = new ArrayMap<>();
- ArrayMap<String, Object> expectedTo = new ArrayMap<>();
- List<Field> fieldsForDiff = getFieldsForDiffCheck(
ZenModeConfig.class, ZEN_MODE_CONFIG_EXEMPT_FIELDS, false);
generateFieldDiffs(c1, c2, fieldsForDiff, expectedFrom, expectedTo);
@@ -656,14 +611,6 @@ public class ZenModeDiffTest extends UiServiceTestCase {
assertEquals("different", automaticDiffs.get("ruleId").getDiffForField("pkg").to());
}
- // Helper method that merges the base exempt fields with fields that are flagged
- private Set getConfigExemptAndFlaggedFields() {
- Set merged = new HashSet();
- merged.addAll(ZEN_MODE_CONFIG_EXEMPT_FIELDS);
- merged.addAll(ZEN_MODE_CONFIG_FLAGGED_FIELDS);
- return merged;
- }
-
// Helper methods for working with configs, policies, rules
// Just makes a zen rule with fields filled in
private ZenModeConfig.ZenRule makeRule() {
@@ -676,20 +623,17 @@ public class ZenModeDiffTest extends UiServiceTestCase {
rule.creationTime = 123;
rule.id = "ruleId";
rule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- rule.modified = false;
rule.name = "name";
rule.setConditionOverride(ZenModeConfig.ZenRule.OVERRIDE_DEACTIVATE);
rule.pkg = "a";
- if (android.app.Flags.modesApi()) {
- rule.allowManualInvocation = true;
- rule.type = AutomaticZenRule.TYPE_SCHEDULE_TIME;
- rule.iconResName = "res";
- rule.triggerDescription = "At night";
- rule.zenDeviceEffects = new ZenDeviceEffects.Builder()
- .setShouldDimWallpaper(true)
- .build();
- rule.userModifiedFields = AutomaticZenRule.FIELD_NAME;
- }
+ rule.allowManualInvocation = true;
+ rule.type = AutomaticZenRule.TYPE_SCHEDULE_TIME;
+ rule.iconResName = "res";
+ rule.triggerDescription = "At night";
+ rule.zenDeviceEffects = new ZenDeviceEffects.Builder()
+ .setShouldDimWallpaper(true)
+ .build();
+ rule.userModifiedFields = AutomaticZenRule.FIELD_NAME;
return rule;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
index a49f5a89b11b..2f0b3ecb593a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -37,7 +37,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.app.Flags;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager.Policy;
@@ -492,8 +491,6 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
@Test
public void testAllowChannels_priorityPackage() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
// Notification with package priority = PRIORITY_MAX (assigned to indicate canBypassDnd)
NotificationRecord r = getNotificationRecord();
r.setPackagePriority(Notification.PRIORITY_MAX);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 31b9cf72584c..0ab11e0cbe3d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -23,7 +23,7 @@ import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
import static android.app.AutomaticZenRule.TYPE_THEATER;
import static android.app.AutomaticZenRule.TYPE_UNKNOWN;
import static android.app.Flags.FLAG_BACKUP_RESTORE_LOGGING;
-import static android.app.Flags.FLAG_MODES_API;
+import static android.app.Flags.FLAG_MODES_CLEANUP_IMPLICIT;
import static android.app.Flags.FLAG_MODES_MULTIUSER;
import static android.app.Flags.FLAG_MODES_UI;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED;
@@ -85,6 +85,7 @@ import static android.service.notification.ZenPolicy.VISUAL_EFFECT_LIGHTS;
import static android.service.notification.ZenPolicy.VISUAL_EFFECT_PEEK;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.LOG_DND_STATE_EVENTS;
+import static com.android.os.dnd.DNDProtoEnums.CONV_IMPORTANT;
import static com.android.os.dnd.DNDProtoEnums.PEOPLE_STARRED;
import static com.android.os.dnd.DNDProtoEnums.ROOT_CONFIG;
import static com.android.os.dnd.DNDProtoEnums.STATE_ALLOW;
@@ -124,7 +125,10 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
+import static java.time.temporal.ChronoUnit.DAYS;
+
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
@@ -219,11 +223,11 @@ import java.io.Reader;
import java.io.StringWriter;
import java.time.Instant;
import java.time.ZoneOffset;
-import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -713,7 +717,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testTotalSilence_consolidatedPolicyDisallowsAll() {
// Start with zen mode off just to make sure global/manual mode isn't doing anything.
mZenModeHelper.mZenMode = ZEN_MODE_OFF;
@@ -746,7 +749,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testAlarmsOnly_consolidatedPolicyOnlyAllowsAlarmsAndMedia() {
// Start with zen mode off just to make sure global/manual mode isn't doing anything.
mZenModeHelper.mZenMode = ZEN_MODE_OFF;
@@ -1136,8 +1138,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testProto() throws InvalidProtocolBufferException {
mZenModeHelper.setManualZenMode(UserHandle.CURRENT, ZEN_MODE_IMPORTANT_INTERRUPTIONS, null,
- Flags.modesApi() ? ORIGIN_USER_IN_SYSTEMUI : ORIGIN_SYSTEM, null,
- "test", CUSTOM_PKG_UID);
+ ORIGIN_USER_IN_SYSTEMUI, null, "test", CUSTOM_PKG_UID);
mZenModeHelper.mConfig.automaticRules = new ArrayMap<>(); // no automatic rules
@@ -1262,7 +1263,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testProtoWithAutoRuleCustomPolicy() throws Exception {
setupZenConfig();
// clear any automatic rules just to make sure
@@ -1304,7 +1304,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testProtoWithAutoRuleWithModifiedFields() throws Exception {
setupZenConfig();
mZenModeHelper.mConfig.automaticRules = new ArrayMap<>();
@@ -2005,7 +2004,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testReadXml_onModesApi_noUpgrade() throws Exception {
// When reading XML for something that is already on the modes API system, make sure no
// rules' policies get changed.
@@ -2053,7 +2051,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testReadXml_upgradeToModesApi_makesCustomPolicies() throws Exception {
// When reading in an XML file written from a pre-modes-API version, confirm that we create
// a custom policy matching the global config for any automatic rule with no specified
@@ -2105,7 +2102,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testReadXml_upgradeToModesApi_fillsInCustomPolicies() throws Exception {
// When reading in an XML file written from a pre-modes-API version, confirm that for an
// underspecified ZenPolicy, we fill in all of the gaps with things from the global config
@@ -2165,7 +2161,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testReadXml_upgradeToModesApi_existingDefaultRulesGetCustomPolicy()
throws Exception {
setupZenConfig();
@@ -2227,7 +2222,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void testReadXml_upgradeToModesUi_resetsImplicitRuleIcon() throws Exception {
setupZenConfig();
mZenModeHelper.mConfig.automaticRules.clear();
@@ -2241,13 +2236,12 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelper.mConfig.automaticRules.put(implicitRuleBeforeModesUi.id,
implicitRuleBeforeModesUi);
// Plus one other normal rule.
- ZenRule anotherRule = newZenRule("other_pkg", Instant.now(), null);
- anotherRule.id = "other_rule";
+ ZenRule anotherRule = newZenRule("other_rule", "other_pkg", Instant.now());
anotherRule.iconResName = "other_icon";
anotherRule.type = TYPE_IMMERSIVE;
mZenModeHelper.mConfig.automaticRules.put(anotherRule.id, anotherRule);
- // Write with pre-modes-ui = (modes_api) version, then re-read.
+ // Write with pre-modes-ui version, then re-read.
ByteArrayOutputStream baos = writeXmlAndPurge(ZenModeConfig.XML_VERSION_MODES_API);
TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
@@ -2265,7 +2259,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void testReadXml_onModesUi_implicitRulesUntouched() throws Exception {
setupZenConfig();
mZenModeHelper.mConfig.automaticRules.clear();
@@ -2279,8 +2273,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
implicitRuleWithModesUi);
// Plus one other normal rule.
- ZenRule anotherRule = newZenRule("other_pkg", Instant.now(), null);
- anotherRule.id = "other_rule";
+ ZenRule anotherRule = newZenRule("other_rule", "other_pkg", Instant.now());
anotherRule.iconResName = "other_icon";
anotherRule.type = TYPE_IMMERSIVE;
mZenModeHelper.mConfig.automaticRules.put(anotherRule.id, anotherRule);
@@ -2342,7 +2335,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// shouldn't update rule that's been modified
ZenModeConfig.ZenRule updatedDefaultRule = new ZenModeConfig.ZenRule();
- updatedDefaultRule.modified = true;
+ updatedDefaultRule.userModifiedFields = AutomaticZenRule.FIELD_NAME;
updatedDefaultRule.enabled = false;
updatedDefaultRule.creationTime = 0;
updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
@@ -2370,8 +2363,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// will update rule that is not enabled and modified
ZenModeConfig.ZenRule customDefaultRule = new ZenModeConfig.ZenRule();
customDefaultRule.pkg = SystemZenRules.PACKAGE_ANDROID;
+ customDefaultRule.userModifiedFields = AutomaticZenRule.FIELD_NAME;
customDefaultRule.enabled = false;
- customDefaultRule.modified = false;
customDefaultRule.creationTime = 0;
customDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
customDefaultRule.name = "Schedule Default Rule";
@@ -2391,7 +2384,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ZenModeConfig.ZenRule ruleAfterUpdating =
mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID);
assertEquals(customDefaultRule.enabled, ruleAfterUpdating.enabled);
- assertEquals(customDefaultRule.modified, ruleAfterUpdating.modified);
+ assertEquals(customDefaultRule.userModifiedFields, ruleAfterUpdating.userModifiedFields);
assertEquals(customDefaultRule.id, ruleAfterUpdating.id);
assertEquals(customDefaultRule.conditionId, ruleAfterUpdating.conditionId);
assertNotEquals(defaultRuleName, ruleAfterUpdating.name); // update name
@@ -2401,8 +2394,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
- public void testDefaultRulesFromConfig_modesApi_getPolicies() {
+ public void testDefaultRulesFromConfig_getPolicies() {
// After mZenModeHelper was created, set some things in the policy so it's changed from
// default.
setupZenConfig();
@@ -2530,7 +2522,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id);
assertTrue(ruleInConfig != null);
assertEquals(zenRule.isEnabled(), ruleInConfig.enabled);
- assertEquals(zenRule.isModified(), ruleInConfig.modified);
assertEquals(zenRule.getConditionId(), ruleInConfig.conditionId);
assertEquals(NotificationManager.zenModeFromInterruptionFilter(
zenRule.getInterruptionFilter(), -1), ruleInConfig.zenMode);
@@ -2551,7 +2542,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id);
assertTrue(ruleInConfig != null);
assertEquals(zenRule.isEnabled(), ruleInConfig.enabled);
- assertEquals(zenRule.isModified(), ruleInConfig.modified);
assertEquals(zenRule.getConditionId(), ruleInConfig.conditionId);
assertEquals(NotificationManager.zenModeFromInterruptionFilter(
zenRule.getInterruptionFilter(), -1), ruleInConfig.zenMode);
@@ -2560,8 +2550,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
- public void testAddAutomaticZenRule_modesApi_fillsInDefaultValues() {
+ public void testAddAutomaticZenRule_fillsInDefaultValues() {
// When a new automatic zen rule is added with only some fields filled in, ensure that
// all unset fields are filled in with device defaults.
@@ -2762,7 +2751,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_fromApp_ignoresHiddenEffects() {
ZenDeviceEffects zde =
new ZenDeviceEffects.Builder()
@@ -2799,7 +2787,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_fromSystem_respectsHiddenEffects() {
ZenDeviceEffects zde = new ZenDeviceEffects.Builder()
.setShouldDisplayGrayscale(true)
@@ -2828,7 +2815,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_fromUser_respectsHiddenEffects() throws Exception {
ZenDeviceEffects zde = new ZenDeviceEffects.Builder()
.setShouldDisplayGrayscale(true)
@@ -2859,7 +2845,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromApp_preservesPreviousHiddenEffects() {
ZenDeviceEffects original = new ZenDeviceEffects.Builder()
.setShouldDisableTapToWake(true)
@@ -2896,7 +2881,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromSystem_updatesHiddenEffects() {
ZenDeviceEffects original = new ZenDeviceEffects.Builder()
.setShouldDisableTapToWake(true)
@@ -2925,7 +2909,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromUser_updatesHiddenEffects() {
ZenDeviceEffects original = new ZenDeviceEffects.Builder()
.setShouldDisableTapToWake(true)
@@ -2958,7 +2941,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_nullPolicy_doesNothing() {
// Test that when updateAutomaticZenRule is called with a null policy, nothing changes
// about the existing policy.
@@ -2985,7 +2967,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_overwritesExistingPolicy() {
// Test that when updating an automatic zen rule with an existing policy, the newly set
// fields overwrite those from the previous policy, but unset fields in the new policy
@@ -3024,7 +3005,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
- @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_withTypeBedtime_replacesDisabledSleeping() {
ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
@@ -3044,7 +3024,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_withTypeBedtime_keepsEnabledSleeping() {
ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
@@ -3065,7 +3044,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_withTypeBedtime_keepsCustomizedSleeping() {
ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
@@ -3086,7 +3064,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void updateAutomaticZenRule_withTypeBedtime_replacesDisabledSleeping() {
ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
@@ -3113,7 +3091,34 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
+ public void getAutomaticZenRules_returnsOwnedRules() {
+ AutomaticZenRule myRule1 = new AutomaticZenRule.Builder("My Rule 1", Uri.parse("1"))
+ .setPackage(mPkg)
+ .setConfigurationActivity(new ComponentName(mPkg, "myActivity"))
+ .build();
+ AutomaticZenRule myRule2 = new AutomaticZenRule.Builder("My Rule 2", Uri.parse("2"))
+ .setPackage(mPkg)
+ .setConfigurationActivity(new ComponentName(mPkg, "myActivity"))
+ .build();
+ AutomaticZenRule otherPkgRule = new AutomaticZenRule.Builder("Other", Uri.parse("3"))
+ .setPackage("com.other.package")
+ .setConfigurationActivity(new ComponentName("com.other.package", "theirActivity"))
+ .build();
+
+ String rule1Id = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg, myRule1,
+ ORIGIN_APP, "reason", CUSTOM_PKG_UID);
+ String rule2Id = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg, myRule2,
+ ORIGIN_APP, "reason", CUSTOM_PKG_UID);
+ String otherRuleId = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT,
+ "com.other.package", otherPkgRule, ORIGIN_APP, "reason", CUSTOM_PKG_UID);
+
+ Map<String, AutomaticZenRule> rules = mZenModeHelper.getAutomaticZenRules(
+ UserHandle.CURRENT, CUSTOM_PKG_UID);
+
+ assertThat(rules.keySet()).containsExactly(rule1Id, rule2Id);
+ }
+
+ @Test
public void testSetManualZenMode() {
setupZenConfig();
@@ -3133,7 +3138,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
@DisableFlags(FLAG_MODES_UI)
public void setManualZenMode_off_snoozesActiveRules() {
for (ZenChangeOrigin origin : ZenChangeOrigin.values()) {
@@ -3172,7 +3176,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setManualZenMode_off_doesNotSnoozeRulesIfFromUserInSystemUi() {
for (ZenChangeOrigin origin : ZenChangeOrigin.values()) {
// Start with an active rule and an inactive rule
@@ -3246,7 +3250,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Turn zen mode on (to important_interruptions)
// Need to additionally call the looper in order to finish the post-apply-config process
mZenModeHelper.setManualZenMode(UserHandle.CURRENT, ZEN_MODE_IMPORTANT_INTERRUPTIONS, null,
- Flags.modesApi() ? ORIGIN_USER_IN_SYSTEMUI : ORIGIN_SYSTEM, "", null, SYSTEM_UID);
+ ORIGIN_USER_IN_SYSTEMUI, "", null, SYSTEM_UID);
// Now turn zen mode off, but via a different package UID -- this should get registered as
// "not an action by the user" because some other app is changing zen mode
@@ -3273,14 +3277,13 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getNewZenMode(0));
assertEquals(DNDProtoEnums.MANUAL_RULE, mZenModeEventLogger.getChangedRuleType(0));
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
- assertThat(mZenModeEventLogger.getFromSystemOrSystemUi(0)).isEqualTo(
- !(Flags.modesUi() || Flags.modesApi()));
+ assertThat(mZenModeEventLogger.getFromSystemOrSystemUi(0)).isFalse();
assertTrue(mZenModeEventLogger.getIsUserAction(0));
assertEquals(SYSTEM_UID, mZenModeEventLogger.getPackageUid(0));
checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0));
// change origin should be populated only under modes_ui
assertThat(mZenModeEventLogger.getChangeOrigin(0)).isEqualTo(
- (Flags.modesApi() && Flags.modesUi()) ? ORIGIN_USER_IN_SYSTEMUI : 0);
+ (Flags.modesUi()) ? ORIGIN_USER_IN_SYSTEMUI : 0);
// and from turning zen mode off:
// - event ID: DND_TURNED_OFF
@@ -3298,11 +3301,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(0, mZenModeEventLogger.getNumRulesActive(1));
assertFalse(mZenModeEventLogger.getIsUserAction(1));
assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(1));
- if (Flags.modesApi()) {
- assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull();
- } else {
- checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1));
- }
+ assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull();
assertThat(mZenModeEventLogger.getChangeOrigin(1)).isEqualTo(
Flags.modesUi() ? ORIGIN_APP : 0);
}
@@ -3334,8 +3333,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Event 2: "User" turns off the automatic rule (sets it to not enabled)
zenRule.setEnabled(false);
mZenModeHelper.updateAutomaticZenRule(UserHandle.CURRENT, id, zenRule,
- Flags.modesApi() ? ORIGIN_USER_IN_SYSTEMUI : ORIGIN_SYSTEM, "",
- SYSTEM_UID);
+ ORIGIN_USER_IN_SYSTEMUI, "", SYSTEM_UID);
AutomaticZenRule systemRule = new AutomaticZenRule("systemRule",
null,
@@ -3345,8 +3343,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String systemId = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT,
mContext.getPackageName(), systemRule,
- Flags.modesApi() ? ORIGIN_USER_IN_SYSTEMUI : ORIGIN_SYSTEM, "test",
- SYSTEM_UID);
+ ORIGIN_USER_IN_SYSTEMUI, "test", SYSTEM_UID);
// Event 3: turn on the system rule
mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, systemId,
@@ -3355,8 +3352,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Event 4: "User" deletes the rule
mZenModeHelper.removeAutomaticZenRule(UserHandle.CURRENT, systemId,
- Flags.modesApi() ? ORIGIN_USER_IN_SYSTEMUI : ORIGIN_SYSTEM, "",
- SYSTEM_UID);
+ ORIGIN_USER_IN_SYSTEMUI, "", SYSTEM_UID);
// In total, this represents 4 events
assertEquals(4, mZenModeEventLogger.numLoggedChanges());
@@ -3394,11 +3390,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertTrue(mZenModeEventLogger.getIsUserAction(1));
assertThat(mZenModeEventLogger.getPackageUid(1)).isEqualTo(
Flags.modesUi() ? CUSTOM_PKG_UID : SYSTEM_UID);
- if (Flags.modesApi()) {
- assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull();
- } else {
- checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1));
- }
+ assertThat(mZenModeEventLogger.getPolicyProto(1)).isNull();
assertThat(mZenModeEventLogger.getChangeOrigin(1)).isEqualTo(
Flags.modesUi() ? ORIGIN_USER_IN_SYSTEMUI : 0);
@@ -3426,7 +3418,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testZenModeEventLog_automaticRuleActivatedFromAppByAppAndUser()
throws IllegalArgumentException {
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
@@ -3816,13 +3807,13 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// Now change apps bypassing to true
ZenModeConfig newConfig = mZenModeHelper.mConfig.copy();
- newConfig.areChannelsBypassingDnd = true;
+ newConfig.hasPriorityChannels = true;
mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, newConfig.toNotificationPolicy(),
ORIGIN_SYSTEM, SYSTEM_UID);
assertEquals(2, mZenModeEventLogger.numLoggedChanges());
// and then back to false, all without changing anything else
- newConfig.areChannelsBypassingDnd = false;
+ newConfig.hasPriorityChannels = false;
mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, newConfig.toNotificationPolicy(),
ORIGIN_SYSTEM, SYSTEM_UID);
assertEquals(3, mZenModeEventLogger.numLoggedChanges());
@@ -3869,10 +3860,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testZenModeEventLog_policyAllowChannels() {
- // when modes_api flag is on, ensure that any change in allow_channels gets logged,
- // even when there are no other changes.
+ // Ensure that any change in allow_channels gets logged, even when there are no other
+ // changes.
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
// Default zen config has allow channels = priority (aka on)
@@ -3919,7 +3909,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testZenModeEventLog_ruleWithInterruptionFilterAll_notLoggedAsDndChange() {
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3961,7 +3950,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testZenModeEventLog_activeRuleTypes() {
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -4050,43 +4038,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @DisableFlags(FLAG_MODES_API)
- public void testUpdateConsolidatedPolicy_preModesApiDefaultRulesOnly_takesGlobalDefault() {
- setupZenConfig();
- // When there's one automatic rule active and it doesn't specify a policy, test that the
- // resulting consolidated policy is one that matches the default rule settings.
- AutomaticZenRule zenRule = new AutomaticZenRule("name",
- null,
- new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
- ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
- null,
- NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT,
- mContext.getPackageName(), zenRule, ORIGIN_SYSTEM, "test", SYSTEM_UID);
-
- // enable the rule
- mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, id,
- new Condition(zenRule.getConditionId(), "", STATE_TRUE),
- ORIGIN_SYSTEM, SYSTEM_UID);
-
- assertEquals(mZenModeHelper.getNotificationPolicy(UserHandle.CURRENT),
- mZenModeHelper.getConsolidatedNotificationPolicy());
-
- // inspect the consolidated policy. Based on setupZenConfig() values.
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowAlarms());
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowMedia());
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowSystem());
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowReminders());
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowCalls());
- assertEquals(PRIORITY_SENDERS_STARRED, mZenModeHelper.mConsolidatedPolicy.allowCallsFrom());
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowMessages());
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowConversations());
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers());
- assertFalse(mZenModeHelper.mConsolidatedPolicy.showBadges());
- }
-
- @Test
- public void testUpdateConsolidatedPolicy_modesApiDefaultRulesOnly_takesDefault() {
+ public void testUpdateConsolidatedPolicy_defaultRulesOnly_takesDefault() {
setupZenConfig();
// When there's one automatic rule active and it doesn't specify a policy, test that the
@@ -4113,53 +4065,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @DisableFlags(FLAG_MODES_API)
- public void testUpdateConsolidatedPolicy_preModesApiCustomPolicyOnly_fillInWithGlobal() {
- setupZenConfig();
-
- // when there's only one automatic rule active and it has a custom policy, make sure that's
- // what the consolidated policy reflects whether or not it's stricter than what the global
- // config would specify.
- ZenPolicy customPolicy = new ZenPolicy.Builder()
- .allowAlarms(true) // more lenient than default
- .allowMedia(true) // more lenient than default
- .allowRepeatCallers(false) // more restrictive than default
- .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE) // more restrictive than default
- .showBadges(true) // more lenient
- .showPeeking(false) // more restrictive
- .build();
-
- AutomaticZenRule zenRule = new AutomaticZenRule("name",
- null,
- new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
- ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
- customPolicy,
- NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT,
- mContext.getPackageName(), zenRule, ORIGIN_SYSTEM, "test", SYSTEM_UID);
-
- // enable the rule; this will update the consolidated policy
- mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, id,
- new Condition(zenRule.getConditionId(), "", STATE_TRUE), ORIGIN_SYSTEM, SYSTEM_UID);
-
- // since this is the only active rule, the consolidated policy should match the custom
- // policy for every field specified, and take default values (from device default or
- // manual policy) for unspecified things
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowAlarms()); // custom
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowMedia()); // custom
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowSystem()); // default
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowReminders()); // default
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowCalls()); // custom
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowMessages()); // default
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowConversations()); // default
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers()); // custom
- assertTrue(mZenModeHelper.mConsolidatedPolicy.showBadges()); // custom
- assertFalse(mZenModeHelper.mConsolidatedPolicy.showPeeking()); // custom
- }
-
- @Test
- @EnableFlags(FLAG_MODES_API)
- public void testUpdateConsolidatedPolicy_modesApiCustomPolicyOnly_fillInWithDefault() {
+ public void testUpdateConsolidatedPolicy_customPolicyOnly_fillInWithDefault() {
setupZenConfig();
// when there's only one automatic rule active and it has a custom policy, make sure that's
@@ -4204,68 +4110,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @DisableFlags(FLAG_MODES_API)
- public void testUpdateConsolidatedPolicy_preModesApiDefaultAndCustomActive_mergesWithGlobal() {
- setupZenConfig();
-
- // when there are two rules active, one inheriting the default policy and one setting its
- // own custom policy, they should be merged to form the most restrictive combination.
-
- // rule 1: no custom policy
- AutomaticZenRule zenRule = new AutomaticZenRule("name",
- null,
- new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
- ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
- null,
- NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT,
- mContext.getPackageName(), zenRule, ORIGIN_SYSTEM, "test", SYSTEM_UID);
-
- // enable rule 1
- mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, id,
- new Condition(zenRule.getConditionId(), "", STATE_TRUE), ORIGIN_SYSTEM, SYSTEM_UID);
-
- // custom policy for rule 2
- ZenPolicy customPolicy = new ZenPolicy.Builder()
- .allowAlarms(true) // more lenient than default
- .allowMedia(true) // more lenient than default
- .allowRepeatCallers(false) // more restrictive than default
- .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE) // more restrictive than default
- .showBadges(true) // more lenient
- .showPeeking(false) // more restrictive
- .build();
-
- AutomaticZenRule zenRule2 = new AutomaticZenRule("name2",
- null,
- new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
- ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
- customPolicy,
- NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id2 = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT,
- mContext.getPackageName(), zenRule2, ORIGIN_SYSTEM, "test", SYSTEM_UID);
-
- // enable rule 2; this will update the consolidated policy
- mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, id2,
- new Condition(zenRule2.getConditionId(), "", STATE_TRUE),
- ORIGIN_SYSTEM, SYSTEM_UID);
-
- // now both rules should be on, and the consolidated policy should reflect the most
- // restrictive option of each of the two
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowAlarms()); // default stricter
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowMedia()); // default stricter
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowSystem()); // default, unset in custom
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowReminders()); // default
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowCalls()); // custom stricter
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowMessages()); // default, unset in custom
- assertTrue(mZenModeHelper.mConsolidatedPolicy.allowConversations()); // default
- assertFalse(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers()); // custom stricter
- assertFalse(mZenModeHelper.mConsolidatedPolicy.showBadges()); // default stricter
- assertFalse(mZenModeHelper.mConsolidatedPolicy.showPeeking()); // custom stricter
- }
-
- @Test
- @EnableFlags(FLAG_MODES_API)
- public void testUpdateConsolidatedPolicy_modesApiDefaultAndCustomActive_mergesWithDefault() {
+ public void testUpdateConsolidatedPolicy_defaultAndCustomActive_mergesWithDefault() {
setupZenConfig();
// when there are two rules active, one inheriting the default policy and one setting its
@@ -4328,7 +4173,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testUpdateConsolidatedPolicy_allowChannels() {
setupZenConfig();
@@ -4377,7 +4221,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testUpdateConsolidatedPolicy_ignoresActiveRulesWithInterruptionFilterAll() {
setupZenConfig();
@@ -4428,7 +4271,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void zenRuleToAutomaticZenRule_allFields() {
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
new String[]{OWNER.getPackageName()});
@@ -4442,7 +4284,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
rule.creationTime = 123;
rule.id = "id";
rule.zenMode = INTERRUPTION_FILTER_ZR;
- rule.modified = true;
rule.name = NAME;
rule.setConditionOverride(OVERRIDE_DEACTIVATE);
rule.pkg = OWNER.getPackageName();
@@ -4473,7 +4314,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void automaticZenRuleToZenRule_allFields() {
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
new String[]{OWNER.getPackageName()});
@@ -4515,7 +4355,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromApp_updatesNameUnlessUserModified() {
// Add a starting rule with the name OriginalName.
AutomaticZenRule azrBase = new AutomaticZenRule.Builder("OriginalName", CONDITION_ID)
@@ -4573,7 +4412,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromUser_updatesBitmaskAndValue() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4627,7 +4465,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromSystemUi_updatesValues() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4678,7 +4515,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromApp_updatesValuesIfRuleNotUserModified() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4754,7 +4590,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_updatesValues() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4777,11 +4612,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue();
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(storedRule.canBeUpdatedByApp()).isTrue();
+ assertThat(storedRule.isUserModified()).isFalse();
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_nullDeviceEffectsUpdate() {
// Adds a starting rule with empty zen policies and device effects
ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
@@ -4809,7 +4643,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_nullPolicyUpdate() {
// Adds a starting rule with set zen policy and empty device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4838,7 +4671,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void automaticZenRuleToZenRule_nullToNonNullPolicyUpdate() {
when(mContext.checkCallingPermission(anyString()))
.thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -4888,7 +4720,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
STATE_DISALLOW);
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(storedRule.canBeUpdatedByApp()).isFalse();
+ assertThat(storedRule.isUserModified()).isTrue();
assertThat(storedRule.zenPolicyUserModifiedFields).isEqualTo(
ZenPolicy.FIELD_ALLOW_CHANNELS
| ZenPolicy.FIELD_PRIORITY_CATEGORY_REMINDERS
@@ -4902,7 +4734,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void automaticZenRuleToZenRule_nullToNonNullDeviceEffectsUpdate() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4931,7 +4762,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue();
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(storedRule.canBeUpdatedByApp()).isFalse();
+ assertThat(storedRule.isUserModified()).isTrue();
assertThat(storedRule.zenDeviceEffectsUserModifiedFields).isEqualTo(
ZenDeviceEffects.FIELD_GRAYSCALE);
}
@@ -5007,7 +4838,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testUpdateAutomaticRule_activated_triggersBroadcast() throws Exception {
setupZenConfig();
@@ -5047,7 +4877,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testUpdateAutomaticRule_deactivatedByUser_triggersBroadcast() throws Exception {
setupZenConfig();
@@ -5091,7 +4920,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testUpdateAutomaticRule_deactivatedByApp_triggersBroadcast() throws Exception {
setupZenConfig();
@@ -5167,7 +4995,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_ruleChanged_deactivatesRule() {
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", CONDITION_ID)
@@ -5191,7 +5018,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_ruleNotChanged_doesNotDeactivateRule() {
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", CONDITION_ID)
@@ -5214,7 +5040,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void updateAutomaticZenRule_ruleChangedByUser_doesNotDeactivateRule() {
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", CONDITION_ID)
@@ -5239,7 +5065,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_ruleChangedByUser_doesNotDeactivateRule_forWatch() {
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)).thenReturn(true);
@@ -5266,7 +5091,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void updateAutomaticZenRule_ruleDisabledByUser_doesNotReactivateOnReenable() {
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", CONDITION_ID)
@@ -5291,7 +5116,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void updateAutomaticZenRule_changeOwnerForSystemRule_allowed() {
when(mContext.checkCallingPermission(anyString()))
.thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -5314,7 +5139,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void updateAutomaticZenRule_changeOwnerForAppOwnedRule_ignored() {
AutomaticZenRule original = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
.setOwner(new ComponentName(mContext.getPackageName(), "old.third.party.cps"))
@@ -5335,7 +5160,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAutomaticZenRule_propagatesOriginToEffectsApplier() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
reset(mDeviceEffectsApplier);
@@ -5358,7 +5182,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_applied() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
verify(mDeviceEffectsApplier).apply(eq(NO_EFFECTS), eq(ORIGIN_INIT));
@@ -5384,7 +5207,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testSettingDeviceEffects_throwsExceptionIfAlreadySet() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
@@ -5394,7 +5216,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_onDeactivateRule_applied() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
@@ -5413,7 +5234,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_changeToConsolidatedEffects_applied() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
verify(mDeviceEffectsApplier).apply(eq(NO_EFFECTS), eq(ORIGIN_INIT));
@@ -5453,7 +5273,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_noChangeToConsolidatedEffects_notApplied() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
verify(mDeviceEffectsApplier).apply(eq(NO_EFFECTS), eq(ORIGIN_INIT));
@@ -5478,7 +5297,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_activeBeforeApplierProvided_appliedWhenProvided() {
ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
String ruleId = addRuleWithEffects(zde);
@@ -5494,7 +5312,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_onUserSwitch_appliedImmediately() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
verify(mDeviceEffectsApplier).apply(eq(NO_EFFECTS), eq(ORIGIN_INIT));
@@ -5522,7 +5339,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI, FLAG_PREVENT_ZEN_DEVICE_EFFECTS_WHILE_DRIVING})
+ @EnableFlags({FLAG_MODES_UI, FLAG_PREVENT_ZEN_DEVICE_EFFECTS_WHILE_DRIVING})
public void testDeviceEffects_allowsGrayscale() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
reset(mDeviceEffectsApplier);
@@ -5539,7 +5356,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI, FLAG_PREVENT_ZEN_DEVICE_EFFECTS_WHILE_DRIVING})
+ @EnableFlags({FLAG_MODES_UI, FLAG_PREVENT_ZEN_DEVICE_EFFECTS_WHILE_DRIVING})
public void testDeviceEffects_whileDriving_avoidsGrayscale() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
reset(mDeviceEffectsApplier);
@@ -5563,7 +5380,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI, FLAG_PREVENT_ZEN_DEVICE_EFFECTS_WHILE_DRIVING})
+ @EnableFlags({FLAG_MODES_UI, FLAG_PREVENT_ZEN_DEVICE_EFFECTS_WHILE_DRIVING})
public void testDeviceEffects_whileDrivingWithGrayscale_allowsGrayscale() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
reset(mDeviceEffectsApplier);
@@ -5594,7 +5411,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_wasCustomized_isRestored() {
// Start with a rule.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5651,7 +5467,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_wasNotCustomized_isNotRestored() {
// Start with a single rule.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5685,7 +5500,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_recreatedButNotByApp_isNotRestored() {
// Start with a single rule.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5736,7 +5550,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_removedByUser_isNotRestored() {
// Start with a single rule.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5779,7 +5592,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void removeAndAddAutomaticZenRule_ifChangingComponent_isAllowedAndDoesNotRestore() {
// Start with a rule.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5824,7 +5637,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAutomaticZenRule_preservedForRestoringByPackageAndConditionId() {
mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS,
PERMISSION_GRANTED); // So that canManageAZR passes although packages don't match.
@@ -5874,7 +5686,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAllZenRules_preservedForRestoring() {
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5898,14 +5709,13 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAllZenRules_fromSystem_deletesPreservedRulesToo() {
mZenModeHelper.mConfig.automaticRules.clear();
// Start with deleted rules from 2 different packages.
Instant now = Instant.ofEpochMilli(1701796461000L);
- ZenRule pkg1Rule = newZenRule("pkg1", now.minus(1, ChronoUnit.DAYS), now);
- ZenRule pkg2Rule = newZenRule("pkg2", now.minus(2, ChronoUnit.DAYS), now);
+ ZenRule pkg1Rule = newDeletedZenRule("1", "pkg1", now.minus(1, DAYS), now);
+ ZenRule pkg2Rule = newDeletedZenRule("2", "pkg2", now.minus(2, DAYS), now);
mZenModeHelper.mConfig.deletedRules.put(ZenModeConfig.deletedRuleKey(pkg1Rule), pkg1Rule);
mZenModeHelper.mConfig.deletedRules.put(ZenModeConfig.deletedRuleKey(pkg2Rule), pkg2Rule);
@@ -5918,7 +5728,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_wasActive_isRestoredAsInactive() {
// Start with a rule.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5968,7 +5777,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_wasSnoozed_isRestoredAsInactive() {
// Start with a rule.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -6023,12 +5831,11 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testRuleCleanup() throws Exception {
Instant now = Instant.ofEpochMilli(1701796461000L);
- Instant yesterday = now.minus(1, ChronoUnit.DAYS);
- Instant aWeekAgo = now.minus(7, ChronoUnit.DAYS);
- Instant twoMonthsAgo = now.minus(60, ChronoUnit.DAYS);
+ Instant yesterday = now.minus(1, DAYS);
+ Instant aWeekAgo = now.minus(7, DAYS);
+ Instant twoMonthsAgo = now.minus(60, DAYS);
mTestClock.setNowMillis(now.toEpochMilli());
when(mPackageManager.getPackageInfo(eq("good_pkg"), anyInt()))
@@ -6041,24 +5848,28 @@ public class ZenModeHelperTest extends UiServiceTestCase {
config.user = 42;
mZenModeHelper.mConfigs.put(42, config);
// okay rules (not deleted, package exists, with a range of creation dates).
- config.automaticRules.put("ar1", newZenRule("good_pkg", now, null));
- config.automaticRules.put("ar2", newZenRule("good_pkg", yesterday, null));
- config.automaticRules.put("ar3", newZenRule("good_pkg", twoMonthsAgo, null));
+ config.automaticRules.put("ar1", newZenRule("ar1", "good_pkg", now));
+ config.automaticRules.put("ar2", newZenRule("ar2", "good_pkg", yesterday));
+ config.automaticRules.put("ar3", newZenRule("ar3", "good_pkg", twoMonthsAgo));
// newish rules for a missing package
- config.automaticRules.put("ar4", newZenRule("bad_pkg", yesterday, null));
+ config.automaticRules.put("ar4", newZenRule("ar4", "bad_pkg", yesterday));
// oldish rules belonging to a missing package
- config.automaticRules.put("ar5", newZenRule("bad_pkg", aWeekAgo, null));
+ config.automaticRules.put("ar5", newZenRule("ar5", "bad_pkg", aWeekAgo));
// rules deleted recently
- config.deletedRules.put("del1", newZenRule("good_pkg", twoMonthsAgo, yesterday));
- config.deletedRules.put("del2", newZenRule("good_pkg", twoMonthsAgo, aWeekAgo));
+ config.deletedRules.put("del1",
+ newDeletedZenRule("del1", "good_pkg", twoMonthsAgo, yesterday));
+ config.deletedRules.put("del2",
+ newDeletedZenRule("del2", "good_pkg", twoMonthsAgo, aWeekAgo));
// rules deleted a long time ago
- config.deletedRules.put("del3", newZenRule("good_pkg", twoMonthsAgo, twoMonthsAgo));
+ config.deletedRules.put("del3",
+ newDeletedZenRule("del3", "good_pkg", twoMonthsAgo, twoMonthsAgo));
// rules for a missing package, created recently and deleted recently
- config.deletedRules.put("del4", newZenRule("bad_pkg", yesterday, now));
+ config.deletedRules.put("del4", newDeletedZenRule("del4", "bad_pkg", yesterday, now));
// rules for a missing package, created a long time ago and deleted recently
- config.deletedRules.put("del5", newZenRule("bad_pkg", twoMonthsAgo, now));
+ config.deletedRules.put("del5", newDeletedZenRule("del5", "bad_pkg", twoMonthsAgo, now));
// rules for a missing package, created a long time ago and deleted a long time ago
- config.deletedRules.put("del6", newZenRule("bad_pkg", twoMonthsAgo, twoMonthsAgo));
+ config.deletedRules.put("del6",
+ newDeletedZenRule("del6", "bad_pkg", twoMonthsAgo, twoMonthsAgo));
mZenModeHelper.onUserSwitched(42); // copies config and cleans it up.
@@ -6068,20 +5879,120 @@ public class ZenModeHelperTest extends UiServiceTestCase {
.containsExactly("del1", "del2", "del4");
}
- private static ZenRule newZenRule(String pkg, Instant createdAt, @Nullable Instant deletedAt) {
+ @Test
+ @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT})
+ public void testRuleCleanup_removesNotRecentlyUsedNotModifiedImplicitRules() throws Exception {
+ Instant now = Instant.ofEpochMilli(1701796461000L);
+ Instant yesterday = now.minus(1, DAYS);
+ Instant aWeekAgo = now.minus(7, DAYS);
+ Instant twoMonthsAgo = now.minus(60, DAYS);
+ Instant aYearAgo = now.minus(365, DAYS);
+ mTestClock.setNowMillis(now.toEpochMilli());
+ when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(new PackageInfo());
+
+ // Set up a config to be loaded, containing a bunch of implicit rules
+ ZenModeConfig config = new ZenModeConfig();
+ config.user = 42;
+ mZenModeHelper.mConfigs.put(42, config);
+ // used recently
+ ZenRule usedRecently1 = newImplicitZenRule("pkg1", aYearAgo, yesterday);
+ ZenRule usedRecently2 = newImplicitZenRule("pkg2", aYearAgo, aWeekAgo);
+ config.automaticRules.put(usedRecently1.id, usedRecently1);
+ config.automaticRules.put(usedRecently2.id, usedRecently2);
+ // not used in a long time
+ ZenRule longUnused = newImplicitZenRule("pkg3", aYearAgo, twoMonthsAgo);
+ config.automaticRules.put(longUnused.id, longUnused);
+ // created a long time ago, before lastActivation tracking
+ ZenRule oldAndLastUsageUnknown = newImplicitZenRule("pkg4", twoMonthsAgo, null);
+ config.automaticRules.put(oldAndLastUsageUnknown.id, oldAndLastUsageUnknown);
+ // created a short time ago, before lastActivation tracking
+ ZenRule newAndLastUsageUnknown = newImplicitZenRule("pkg5", aWeekAgo, null);
+ config.automaticRules.put(newAndLastUsageUnknown.id, newAndLastUsageUnknown);
+ // not used in a long time, but was customized by user
+ ZenRule longUnusedButCustomized = newImplicitZenRule("pkg6", aYearAgo, twoMonthsAgo);
+ longUnusedButCustomized.zenPolicyUserModifiedFields = ZenPolicy.FIELD_CONVERSATIONS;
+ config.automaticRules.put(longUnusedButCustomized.id, longUnusedButCustomized);
+ // created a long time ago, before lastActivation tracking, and was customized by user
+ ZenRule oldAndLastUsageUnknownAndCustomized = newImplicitZenRule("pkg7", twoMonthsAgo,
+ null);
+ oldAndLastUsageUnknownAndCustomized.userModifiedFields = AutomaticZenRule.FIELD_ICON;
+ config.automaticRules.put(oldAndLastUsageUnknownAndCustomized.id,
+ oldAndLastUsageUnknownAndCustomized);
+
+ mZenModeHelper.onUserSwitched(42); // copies config and cleans it up.
+
+ // The recently used OR modified OR last-used-unknown rules stay.
+ assertThat(mZenModeHelper.mConfig.automaticRules.values())
+ .comparingElementsUsing(IGNORE_METADATA)
+ .containsExactly(usedRecently1, usedRecently2, oldAndLastUsageUnknown,
+ newAndLastUsageUnknown, longUnusedButCustomized,
+ oldAndLastUsageUnknownAndCustomized);
+ }
+
+ @Test
+ @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT})
+ public void testRuleCleanup_assignsLastActivationToImplicitRules() throws Exception {
+ Instant now = Instant.ofEpochMilli(1701796461000L);
+ Instant aWeekAgo = now.minus(7, DAYS);
+ Instant aYearAgo = now.minus(365, DAYS);
+ mTestClock.setNowMillis(now.toEpochMilli());
+ when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(new PackageInfo());
+
+ // Set up a config to be loaded, containing implicit rules.
+ ZenModeConfig config = new ZenModeConfig();
+ config.user = 42;
+ mZenModeHelper.mConfigs.put(42, config);
+ // with last activation known
+ ZenRule usedRecently = newImplicitZenRule("pkg1", aYearAgo, aWeekAgo);
+ config.automaticRules.put(usedRecently.id, usedRecently);
+ // created a long time ago, with last activation unknown
+ ZenRule oldAndLastUsageUnknown = newImplicitZenRule("pkg4", aYearAgo, null);
+ config.automaticRules.put(oldAndLastUsageUnknown.id, oldAndLastUsageUnknown);
+ // created a short time ago, with last activation unknown
+ ZenRule newAndLastUsageUnknown = newImplicitZenRule("pkg5", aWeekAgo, null);
+ config.automaticRules.put(newAndLastUsageUnknown.id, newAndLastUsageUnknown);
+
+ mZenModeHelper.onUserSwitched(42); // copies config and cleans it up.
+
+ // All rules stayed.
+ usedRecently = getZenRule(usedRecently.id);
+ oldAndLastUsageUnknown = getZenRule(oldAndLastUsageUnknown.id);
+ newAndLastUsageUnknown = getZenRule(newAndLastUsageUnknown.id);
+
+ // The rules with an unknown last usage have been assigned a placeholder one.
+ assertThat(usedRecently.lastActivation).isEqualTo(aWeekAgo);
+ assertThat(oldAndLastUsageUnknown.lastActivation).isEqualTo(now);
+ assertThat(newAndLastUsageUnknown.lastActivation).isEqualTo(now);
+ }
+
+ private static ZenRule newDeletedZenRule(String id, String pkg, Instant createdAt,
+ @NonNull Instant deletedAt) {
+ ZenRule rule = newZenRule(id, pkg, createdAt);
+ rule.deletionInstant = deletedAt;
+ return rule;
+ }
+
+ private static ZenRule newImplicitZenRule(String pkg, @NonNull Instant createdAt,
+ @Nullable Instant lastActivatedAt) {
+ ZenRule implicitRule = newZenRule(implicitRuleId(pkg), pkg, createdAt);
+ implicitRule.lastActivation = lastActivatedAt;
+ return implicitRule;
+ }
+
+ private static ZenRule newZenRule(String id, String pkg, Instant createdAt) {
ZenRule rule = new ZenRule();
+ rule.id = id;
rule.pkg = pkg;
rule.creationTime = createdAt.toEpochMilli();
rule.enabled = true;
- rule.deletionInstant = deletedAt;
+ rule.deletionInstant = null;
// Plus stuff so that isValidAutomaticRule() passes
- rule.name = "A rule from " + pkg + " created on " + createdAt;
+ rule.name = "Rule " + id;
rule.conditionId = Uri.parse(rule.name);
return rule;
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void getAutomaticZenRuleState_ownedRule_returnsRuleState() {
String id = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT,
mContext.getPackageName(),
@@ -6112,14 +6023,13 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void getAutomaticZenRuleState_notOwnedRule_returnsStateUnknown() {
// Assume existence of a system-owned rule that is currently ACTIVE.
- ZenRule systemRule = newZenRule("android", Instant.now(), null);
+ ZenRule systemRule = newZenRule("systemRule", "android", Instant.now());
systemRule.zenMode = ZEN_MODE_ALARMS;
systemRule.condition = new Condition(systemRule.conditionId, "on", Condition.STATE_TRUE);
ZenModeConfig config = mZenModeHelper.mConfig.copy();
- config.automaticRules.put("systemRule", systemRule);
+ config.automaticRules.put(systemRule.id, systemRule);
mZenModeHelper.setConfig(config, null, ORIGIN_INIT, "", SYSTEM_UID);
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS);
@@ -6128,15 +6038,14 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void setAutomaticZenRuleState_idForNotOwnedRule_ignored() {
// Assume existence of an other-package-owned rule that is currently ACTIVE.
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
- ZenRule otherRule = newZenRule("another.package", Instant.now(), null);
+ ZenRule otherRule = newZenRule("otherRule", "another.package", Instant.now());
otherRule.zenMode = ZEN_MODE_ALARMS;
otherRule.condition = new Condition(otherRule.conditionId, "on", Condition.STATE_TRUE);
ZenModeConfig config = mZenModeHelper.mConfig.copy();
- config.automaticRules.put("otherRule", otherRule);
+ config.automaticRules.put(otherRule.id, otherRule);
mZenModeHelper.setConfig(config, null, ORIGIN_INIT, "", SYSTEM_UID);
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS);
@@ -6149,15 +6058,14 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void setAutomaticZenRuleStateFromConditionProvider_conditionForNotOwnedRule_ignored() {
// Assume existence of an other-package-owned rule that is currently ACTIVE.
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
- ZenRule otherRule = newZenRule("another.package", Instant.now(), null);
+ ZenRule otherRule = newZenRule("otherRule", "another.package", Instant.now());
otherRule.zenMode = ZEN_MODE_ALARMS;
otherRule.condition = new Condition(otherRule.conditionId, "on", Condition.STATE_TRUE);
ZenModeConfig config = mZenModeHelper.mConfig.copy();
- config.automaticRules.put("otherRule", otherRule);
+ config.automaticRules.put(otherRule.id, otherRule);
mZenModeHelper.setConfig(config, null, ORIGIN_INIT, "", SYSTEM_UID);
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS);
@@ -6171,7 +6079,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testCallbacks_policy() throws Exception {
setupZenConfig();
assertThat(mZenModeHelper.getNotificationPolicy(UserHandle.CURRENT).allowReminders())
@@ -6193,7 +6100,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void testCallbacks_consolidatedPolicy() throws Exception {
assertThat(mZenModeHelper.getConsolidatedNotificationPolicy().allowMedia()).isTrue();
SettableFuture<Policy> futureConsolidatedPolicy = SettableFuture.create();
@@ -6219,7 +6125,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_createsImplicitRuleAndActivatesIt() {
mZenModeHelper.mConfig.automaticRules.clear();
@@ -6235,7 +6140,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_updatesImplicitRuleAndActivatesIt() {
mZenModeHelper.mConfig.automaticRules.clear();
@@ -6257,7 +6161,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_ruleCustomized_doesNotUpdateRule() {
mZenModeHelper.mConfig.automaticRules.clear();
String pkg = mContext.getPackageName();
@@ -6290,7 +6193,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_ruleCustomizedButNotFilter_updatesRule() {
mZenModeHelper.mConfig.automaticRules.clear();
String pkg = mContext.getPackageName();
@@ -6322,7 +6224,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_modeOff_deactivatesImplicitRule() {
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, mPkg, CUSTOM_PKG_UID,
@@ -6339,7 +6240,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_modeOffButNoPreviousRule_ignored() {
mZenModeHelper.mConfig.automaticRules.clear();
@@ -6350,7 +6250,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_update_unsnoozesRule() {
mZenModeHelper.mConfig.automaticRules.clear();
@@ -6375,7 +6274,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void applyGlobalZenModeAsImplicitZenRule_again_refreshesRuleName() {
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT,
@@ -6394,7 +6293,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void applyGlobalZenModeAsImplicitZenRule_again_doesNotChangeCustomizedRuleName() {
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT,
@@ -6420,19 +6319,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @DisableFlags(FLAG_MODES_API)
- public void applyGlobalZenModeAsImplicitZenRule_flagOff_ignored() {
- mZenModeHelper.mConfig.automaticRules.clear();
-
- withoutWtfCrash(
- () -> mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT,
- CUSTOM_PKG_NAME, CUSTOM_PKG_UID, ZEN_MODE_IMPORTANT_INTERRUPTIONS));
-
- assertThat(mZenModeHelper.mConfig.automaticRules).isEmpty();
- }
-
- @Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalPolicyAsImplicitZenRule_createsImplicitRule() {
mZenModeHelper.mConfig.automaticRules.clear();
@@ -6457,7 +6343,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalPolicyAsImplicitZenRule_updatesImplicitRule() {
mZenModeHelper.mConfig.automaticRules.clear();
@@ -6489,7 +6374,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalPolicyAsImplicitZenRule_ruleCustomized_doesNotUpdateRule() {
mZenModeHelper.mConfig.automaticRules.clear();
String pkg = mContext.getPackageName();
@@ -6532,7 +6416,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void applyGlobalPolicyAsImplicitZenRule_ruleCustomizedButNotZenPolicy_updatesRule() {
mZenModeHelper.mConfig.automaticRules.clear();
String pkg = mContext.getPackageName();
@@ -6572,7 +6455,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void applyGlobalPolicyAsImplicitZenRule_again_refreshesRuleName() {
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(UserHandle.CURRENT,
@@ -6591,7 +6474,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void applyGlobalPolicyAsImplicitZenRule_again_doesNotChangeCustomizedRuleName() {
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(UserHandle.CURRENT,
@@ -6617,19 +6500,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @DisableFlags(FLAG_MODES_API)
- public void applyGlobalPolicyAsImplicitZenRule_flagOff_ignored() {
- mZenModeHelper.mConfig.automaticRules.clear();
-
- withoutWtfCrash(
- () -> mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(UserHandle.CURRENT,
- CUSTOM_PKG_NAME, CUSTOM_PKG_UID, new Policy(0, 0, 0)));
-
- assertThat(mZenModeHelper.mConfig.automaticRules).isEmpty();
- }
-
- @Test
- @EnableFlags(FLAG_MODES_API)
public void getNotificationPolicyFromImplicitZenRule_returnsSetPolicy() {
Policy writtenPolicy = new Policy(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS,
PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED,
@@ -6645,7 +6515,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
@DisableFlags(FLAG_MODES_UI)
public void getNotificationPolicyFromImplicitZenRule_ruleWithoutPolicy_copiesGlobalPolicy() {
// Implicit rule will get the global policy at the time of rule creation.
@@ -6665,7 +6534,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void getNotificationPolicyFromImplicitZenRule_noImplicitRule_returnsGlobalPolicy() {
Policy policy = new Policy(PRIORITY_CATEGORY_CALLS, PRIORITY_SENDERS_STARRED, 0);
mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, policy, ORIGIN_APP,
@@ -6680,7 +6548,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
@DisableFlags(FLAG_MODES_UI)
public void setNotificationPolicy_updatesRulePolicies_ifRulePolicyIsDefaultOrGlobalPolicy() {
ZenPolicy defaultZenPolicy = mZenModeHelper.getDefaultZenPolicy();
@@ -6726,7 +6593,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
public void addRule_iconIdWithResourceNameTooLong_ignoresIcon() {
int resourceId = 999;
String veryLongResourceName = "com.android.server.notification:drawable/"
@@ -6745,7 +6611,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setManualZenRuleDeviceEffects_noPreexistingMode() {
ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
.setShouldDimWallpaper(true)
@@ -6759,7 +6625,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setManualZenRuleDeviceEffects_preexistingMode() {
mZenModeHelper.setManualZenMode(UserHandle.CURRENT, ZEN_MODE_OFF, Uri.EMPTY,
ORIGIN_USER_IN_SYSTEMUI, "create manual rule", "settings", SYSTEM_UID);
@@ -6776,7 +6642,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void addAutomaticZenRule_startsDisabled_recordsDisabledOrigin() {
AutomaticZenRule startsDisabled = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
.setOwner(new ComponentName(mPkg, "SomeProvider"))
@@ -6792,7 +6658,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void updateAutomaticZenRule_disabling_recordsDisabledOrigin() {
AutomaticZenRule startsEnabled = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
.setOwner(new ComponentName(mPkg, "SomeProvider"))
@@ -6815,7 +6681,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void updateAutomaticZenRule_keepingDisabled_preservesPreviousDisabledOrigin() {
AutomaticZenRule startsEnabled = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
.setOwner(new ComponentName(mPkg, "SomeProvider"))
@@ -6845,7 +6711,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void updateAutomaticZenRule_enabling_clearsDisabledOrigin() {
AutomaticZenRule startsEnabled = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
.setOwner(new ComponentName(mPkg, "SomeProvider"))
@@ -6875,7 +6741,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_manualActivation_appliesOverride() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
.setPackage(mPkg)
@@ -6893,7 +6759,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_manualActivationAndThenDeactivation_removesOverride() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
.setPackage(mPkg)
@@ -6930,7 +6796,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_manualDeactivationAndThenReactivation_removesOverride() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
.setPackage(mPkg)
@@ -6976,7 +6842,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_manualDeactivation_appliesOverride() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
.setPackage(mPkg)
@@ -7002,7 +6868,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_ifManualActive_appCannotDeactivateBeforeActivating() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
.setPackage(mPkg)
@@ -7039,7 +6905,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_ifManualInactive_appCannotReactivateBeforeDeactivating() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
.setPackage(mPkg)
@@ -7085,7 +6951,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_withActivationOverride_userActionFromAppCanDeactivate() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
.setPackage(mPkg)
@@ -7109,7 +6975,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_withDeactivationOverride_userActionFromAppCanActivate() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
.setPackage(mPkg)
@@ -7140,7 +7006,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_manualActionFromApp_isNotOverride() {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
.setPackage(mPkg)
@@ -7165,7 +7031,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_implicitRuleManualActivation_doesNotUseOverride() {
mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS,
PERMISSION_GRANTED); // So that canManageAZR succeeds.
@@ -7188,7 +7054,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_implicitRuleManualDeactivation_doesNotUseOverride() {
mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS,
PERMISSION_GRANTED); // So that canManageAZR succeeds.
@@ -7214,24 +7080,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @DisableFlags({FLAG_MODES_API, FLAG_MODES_UI})
- public void testDefaultConfig_preModesApi_rulesAreBare() {
- // Create a new user, which should get a copy of the default policy.
- mZenModeHelper.onUserSwitched(101);
-
- ZenRule eventsRule = mZenModeHelper.mConfig.automaticRules.get(
- ZenModeConfig.EVENTS_OBSOLETE_RULE_ID);
-
- assertThat(eventsRule).isNotNull();
- assertThat(eventsRule.zenPolicy).isNull();
- assertThat(eventsRule.type).isEqualTo(TYPE_UNKNOWN);
- assertThat(eventsRule.triggerDescription).isNull();
- }
-
- @Test
- @EnableFlags(FLAG_MODES_API)
@DisableFlags(FLAG_MODES_UI)
- public void testDefaultConfig_modesApi_rulesHaveFullPolicy() {
+ public void testDefaultConfig_rulesHaveFullPolicy() {
// Create a new user, which should get a copy of the default policy.
mZenModeHelper.onUserSwitched(201);
@@ -7245,7 +7095,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void testDefaultConfig_modesUi_rulesHaveFullPolicy() {
// Create a new user, which should get a copy of the default policy.
mZenModeHelper.onUserSwitched(301);
@@ -7260,7 +7110,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_withManualActivation_activeOnReboot()
throws Exception {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
@@ -7298,7 +7148,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void setAutomaticZenRuleState_withManualDeactivation_clearedOnReboot()
throws Exception {
AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
@@ -7336,7 +7186,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_withoutPolicy_getsItsOwnInstanceOfDefaultPolicy() {
// Add a rule without policy -> uses default config
AutomaticZenRule azr = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
@@ -7352,7 +7201,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void readXml_withDisabledEventsRule_deletesIt() throws Exception {
ZenRule rule = new ZenRule();
rule.id = ZenModeConfig.EVENTS_OBSOLETE_RULE_ID;
@@ -7372,7 +7221,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void readXml_withEnabledEventsRule_keepsIt() throws Exception {
ZenRule rule = new ZenRule();
rule.id = ZenModeConfig.EVENTS_OBSOLETE_RULE_ID;
@@ -7392,7 +7241,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
- @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ @EnableFlags(FLAG_MODES_UI)
public void updateHasPriorityChannels_keepsChannelSettings() {
setupZenConfig();
@@ -7512,6 +7361,125 @@ public class ZenModeHelperTest extends UiServiceTestCase {
"config: setAzrStateFromCps: cond/cond (ORIGIN_APP) from uid " + CUSTOM_PKG_UID);
}
+ @Test
+ @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT})
+ public void setAutomaticZenRuleState_updatesLastActivation() {
+ String ruleOne = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg,
+ new AutomaticZenRule.Builder("rule", CONDITION_ID)
+ .setConfigurationActivity(new ComponentName(mPkg, "cls"))
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build(),
+ ORIGIN_APP, "reason", CUSTOM_PKG_UID);
+ String ruleTwo = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg,
+ new AutomaticZenRule.Builder("unrelated", Uri.parse("other.condition"))
+ .setConfigurationActivity(new ComponentName(mPkg, "cls"))
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build(),
+ ORIGIN_APP, "reason", CUSTOM_PKG_UID);
+
+ assertThat(getZenRule(ruleOne).lastActivation).isNull();
+ assertThat(getZenRule(ruleTwo).lastActivation).isNull();
+
+ Instant firstActivation = Instant.ofEpochMilli(100);
+ mTestClock.setNow(firstActivation);
+ mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleOne, CONDITION_TRUE,
+ ORIGIN_APP, CUSTOM_PKG_UID);
+
+ assertThat(getZenRule(ruleOne).lastActivation).isEqualTo(firstActivation);
+ assertThat(getZenRule(ruleTwo).lastActivation).isNull();
+
+ mTestClock.setNow(Instant.ofEpochMilli(300));
+ mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleOne, CONDITION_FALSE,
+ ORIGIN_APP, CUSTOM_PKG_UID);
+
+ assertThat(getZenRule(ruleOne).lastActivation).isEqualTo(firstActivation);
+ assertThat(getZenRule(ruleTwo).lastActivation).isNull();
+
+ Instant secondActivation = Instant.ofEpochMilli(500);
+ mTestClock.setNow(secondActivation);
+ mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleOne, CONDITION_TRUE,
+ ORIGIN_APP, CUSTOM_PKG_UID);
+
+ assertThat(getZenRule(ruleOne).lastActivation).isEqualTo(secondActivation);
+ assertThat(getZenRule(ruleTwo).lastActivation).isNull();
+ }
+
+ @Test
+ @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT})
+ public void setManualZenMode_updatesLastActivation() {
+ assertThat(mZenModeHelper.mConfig.manualRule.lastActivation).isNull();
+ Instant instant = Instant.ofEpochMilli(100);
+ mTestClock.setNow(instant);
+
+ mZenModeHelper.setManualZenMode(UserHandle.CURRENT, ZEN_MODE_ALARMS, null,
+ ORIGIN_USER_IN_SYSTEMUI, "reason", "systemui", SYSTEM_UID);
+
+ assertThat(mZenModeHelper.mConfig.manualRule.lastActivation).isEqualTo(instant);
+ }
+
+ @Test
+ @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT})
+ public void applyGlobalZenModeAsImplicitZenRule_updatesLastActivation() {
+ Instant instant = Instant.ofEpochMilli(100);
+ mTestClock.setNow(instant);
+
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME,
+ CUSTOM_PKG_UID, ZEN_MODE_ALARMS);
+
+ ZenRule implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME));
+ assertThat(implicitRule.lastActivation).isEqualTo(instant);
+ }
+
+ @Test
+ @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT})
+ public void setAutomaticZenRuleState_notChangingActiveState_doesNotUpdateLastActivation() {
+ String ruleId = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg,
+ new AutomaticZenRule.Builder("rule", CONDITION_ID)
+ .setConfigurationActivity(new ComponentName(mPkg, "cls"))
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build(),
+ ORIGIN_APP, "reason", CUSTOM_PKG_UID);
+
+ assertThat(getZenRule(ruleId).lastActivation).isNull();
+
+ // Manual activation comes first
+ Instant firstActivation = Instant.ofEpochMilli(100);
+ mTestClock.setNow(firstActivation);
+ mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleId, CONDITION_TRUE,
+ ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
+
+ assertThat(getZenRule(ruleId).lastActivation).isEqualTo(firstActivation);
+
+ // Now the app says the rule should be active (assume it's on a schedule, and the app
+ // doesn't listen to broadcasts so it doesn't know an override was present). This doesn't
+ // change the activation state.
+ mTestClock.setNow(Instant.ofEpochMilli(300));
+ mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleId, CONDITION_TRUE,
+ ORIGIN_APP, CUSTOM_PKG_UID);
+
+ assertThat(getZenRule(ruleId).lastActivation).isEqualTo(firstActivation);
+ }
+
+ @Test
+ @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT})
+ public void addOrUpdateRule_doesNotUpdateLastActivation() {
+ AutomaticZenRule azr = new AutomaticZenRule.Builder("rule", CONDITION_ID)
+ .setConfigurationActivity(new ComponentName(mPkg, "cls"))
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build();
+
+ String ruleId = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg, azr,
+ ORIGIN_APP, "reason", CUSTOM_PKG_UID);
+
+ assertThat(getZenRule(ruleId).lastActivation).isNull();
+
+ mZenModeHelper.updateAutomaticZenRule(UserHandle.CURRENT, ruleId,
+ new AutomaticZenRule.Builder(azr).setName("New name").build(), ORIGIN_APP, "reason",
+ CUSTOM_PKG_UID);
+
+ assertThat(getZenRule(ruleId).lastActivation).isNull();
+ }
+
private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode,
@Nullable ZenPolicy zenPolicy) {
ZenRule rule = new ZenRule();
@@ -7529,22 +7497,27 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
private static final Correspondence<ZenRule, ZenRule> IGNORE_METADATA =
- Correspondence.transforming(zr -> {
- Parcel p = Parcel.obtain();
- try {
- zr.writeToParcel(p, 0);
- p.setDataPosition(0);
- ZenRule copy = new ZenRule(p);
- copy.creationTime = 0;
- copy.userModifiedFields = 0;
- copy.zenPolicyUserModifiedFields = 0;
- copy.zenDeviceEffectsUserModifiedFields = 0;
- return copy;
- } finally {
- p.recycle();
- }
- },
- "Ignoring timestamp and userModifiedFields");
+ Correspondence.transforming(
+ ZenModeHelperTest::cloneWithoutMetadata,
+ ZenModeHelperTest::cloneWithoutMetadata,
+ "Ignoring timestamps and userModifiedFields");
+
+ private static ZenRule cloneWithoutMetadata(ZenRule rule) {
+ Parcel p = Parcel.obtain();
+ try {
+ rule.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ ZenRule copy = new ZenRule(p);
+ copy.creationTime = 0;
+ copy.userModifiedFields = 0;
+ copy.zenPolicyUserModifiedFields = 0;
+ copy.zenDeviceEffectsUserModifiedFields = 0;
+ copy.lastActivation = null;
+ return copy;
+ } finally {
+ p.recycle();
+ }
+ }
private ZenRule expectedImplicitRule(String ownerPkg, int zenMode, ZenPolicy policy,
@Nullable Boolean conditionActive) {
@@ -7574,7 +7547,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
return rule;
}
- // TODO: b/310620812 - Update setup methods to include allowChannels() when MODES_API is inlined
private void setupZenConfig() {
Policy customPolicy = new Policy(PRIORITY_CATEGORY_REMINDERS
| PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES
@@ -7583,7 +7555,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
PRIORITY_SENDERS_STARRED,
PRIORITY_SENDERS_STARRED,
SUPPRESSED_EFFECT_BADGE,
- 0,
+ 0, // allows priority channels.
CONVERSATION_SENDERS_IMPORTANT);
mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, customPolicy, ORIGIN_UNKNOWN, 1);
if (!Flags.modesUi()) {
@@ -7599,8 +7571,11 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(STATE_ALLOW, dndProto.getCalls().getNumber());
assertEquals(PEOPLE_STARRED, dndProto.getAllowCallsFrom().getNumber());
assertEquals(STATE_ALLOW, dndProto.getMessages().getNumber());
+ assertEquals(PEOPLE_STARRED, dndProto.getAllowMessagesFrom().getNumber());
assertEquals(STATE_ALLOW, dndProto.getEvents().getNumber());
assertEquals(STATE_ALLOW, dndProto.getRepeatCallers().getNumber());
+ assertEquals(STATE_ALLOW, dndProto.getConversations().getNumber());
+ assertEquals(CONV_IMPORTANT, dndProto.getAllowConversationsFrom().getNumber());
assertEquals(STATE_ALLOW, dndProto.getFullscreen().getNumber());
assertEquals(STATE_ALLOW, dndProto.getLights().getNumber());
assertEquals(STATE_ALLOW, dndProto.getPeek().getNumber());
@@ -7616,7 +7591,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
return;
}
- // When modes_api flag is on, the default zen config is the device defaults.
+ // The default zen config is the device defaults.
assertThat(dndProto.getAlarms().getNumber()).isEqualTo(STATE_ALLOW);
assertThat(dndProto.getMedia().getNumber()).isEqualTo(STATE_ALLOW);
assertThat(dndProto.getSystem().getNumber()).isEqualTo(STATE_DISALLOW);
@@ -7627,6 +7602,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertThat(dndProto.getAllowMessagesFrom().getNumber()).isEqualTo(PEOPLE_STARRED);
assertThat(dndProto.getEvents().getNumber()).isEqualTo(STATE_DISALLOW);
assertThat(dndProto.getRepeatCallers().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getConversations().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getAllowConversationsFrom().getNumber()).isEqualTo(CONV_IMPORTANT);
assertThat(dndProto.getFullscreen().getNumber()).isEqualTo(STATE_DISALLOW);
assertThat(dndProto.getLights().getNumber()).isEqualTo(STATE_DISALLOW);
assertThat(dndProto.getPeek().getNumber()).isEqualTo(STATE_DISALLOW);
@@ -7634,6 +7611,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertThat(dndProto.getBadge().getNumber()).isEqualTo(STATE_ALLOW);
assertThat(dndProto.getAmbient().getNumber()).isEqualTo(STATE_DISALLOW);
assertThat(dndProto.getNotificationList().getNumber()).isEqualTo(STATE_ALLOW);
+ assertThat(dndProto.getAllowChannels().getNumber()).isEqualTo(
+ DNDProtoEnums.CHANNEL_POLICY_PRIORITY);
}
private static String getZenLog() {
@@ -7642,16 +7621,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
return zenLogWriter.toString();
}
- private static void withoutWtfCrash(Runnable test) {
- Log.TerribleFailureHandler oldHandler = Log.setWtfHandler((tag, what, system) -> {
- });
- try {
- test.run();
- } finally {
- Log.setWtfHandler(oldHandler);
- }
- }
-
/**
* Wrapper to use TypedXmlPullParser as XmlResourceParser for Resources.getXml()
*/
@@ -7954,6 +7923,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
return mNowMillis;
}
+ private void setNow(Instant instant) {
+ mNowMillis = instant.toEpochMilli();
+ }
+
private void setNowMillis(long millis) {
mNowMillis = millis;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
index 6433b76defc3..8b9376454c0f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
-import android.app.Flags;
import android.os.Parcel;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenPolicy;
@@ -34,7 +33,6 @@ import com.android.server.UiServiceTestCase;
import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,11 +48,6 @@ public class ZenPolicyTest extends UiServiceTestCase {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
- @Before
- public final void setUp() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
- }
-
@Test
public void testZenPolicyApplyAllowedToDisallowed() {
ZenPolicy.Builder builder = new ZenPolicy.Builder();
@@ -207,8 +200,6 @@ public class ZenPolicyTest extends UiServiceTestCase {
@Test
public void testZenPolicyApplyChannels_applyUnset() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenPolicy.Builder builder = new ZenPolicy.Builder();
ZenPolicy unset = builder.build();
@@ -223,8 +214,6 @@ public class ZenPolicyTest extends UiServiceTestCase {
@Test
public void testZenPolicyApplyChannels_applyStricter() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenPolicy.Builder builder = new ZenPolicy.Builder();
builder.allowPriorityChannels(false);
ZenPolicy none = builder.build();
@@ -239,8 +228,6 @@ public class ZenPolicyTest extends UiServiceTestCase {
@Test
public void testZenPolicyApplyChannels_applyLooser() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenPolicy.Builder builder = new ZenPolicy.Builder();
builder.allowPriorityChannels(false);
ZenPolicy none = builder.build();
@@ -255,8 +242,6 @@ public class ZenPolicyTest extends UiServiceTestCase {
@Test
public void testZenPolicyApplyChannels_applySet() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenPolicy.Builder builder = new ZenPolicy.Builder();
ZenPolicy unset = builder.build();
@@ -270,8 +255,6 @@ public class ZenPolicyTest extends UiServiceTestCase {
@Test
public void testZenPolicyOverwrite_allUnsetPolicies() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenPolicy.Builder builder = new ZenPolicy.Builder();
ZenPolicy unset = builder.build();
@@ -292,8 +275,6 @@ public class ZenPolicyTest extends UiServiceTestCase {
@Test
public void testZenPolicyOverwrite_someOverlappingFields_takeNewPolicy() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenPolicy p1 = new ZenPolicy.Builder()
.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
.allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED)
@@ -375,7 +356,6 @@ public class ZenPolicyTest extends UiServiceTestCase {
@Test
public void testEmptyZenPolicy_emptyChannels() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
ZenPolicy.Builder builder = new ZenPolicy.Builder();
ZenPolicy policy = builder.build();
@@ -688,22 +668,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
}
@Test
- public void testAllowChannels_noFlag() {
- mSetFlagsRule.disableFlags(Flags.FLAG_MODES_API);
-
- // allowChannels should be unset, not be modifiable, and not show up in any output
- ZenPolicy.Builder builder = new ZenPolicy.Builder();
- builder.allowPriorityChannels(true);
- ZenPolicy policy = builder.build();
-
- assertThat(policy.getPriorityChannelsAllowed()).isEqualTo(ZenPolicy.STATE_UNSET);
- assertThat(policy.toString().contains("allowChannels")).isFalse();
- }
-
- @Test
public void testAllowChannels() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
// allow priority channels
ZenPolicy.Builder builder = new ZenPolicy.Builder();
builder.allowPriorityChannels(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 3c74ad06a21f..a9be47d71213 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -509,6 +509,32 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase {
assertThat(mSupervisor.mOpaqueContainerHelper.isOpaque(rootTask)).isTrue();
}
+ @Test
+ public void testOpaque_nonLeafTaskFragmentWithDirectActivity_opaque() {
+ final ActivityRecord directChildActivity = new ActivityBuilder(mAtm).setCreateTask(true)
+ .build();
+ directChildActivity.setOccludesParent(true);
+ final Task nonLeafTask = directChildActivity.getTask();
+ final TaskFragment directChildFragment = new TaskFragment(mAtm, new Binder(),
+ true /* createdByOrganizer */, false /* isEmbedded */);
+ nonLeafTask.addChild(directChildFragment, 0);
+
+ assertThat(mSupervisor.mOpaqueContainerHelper.isOpaque(nonLeafTask)).isTrue();
+ }
+
+ @Test
+ public void testOpaque_nonLeafTaskFragmentWithDirectActivity_transparent() {
+ final ActivityRecord directChildActivity = new ActivityBuilder(mAtm).setCreateTask(true)
+ .build();
+ directChildActivity.setOccludesParent(false);
+ final Task nonLeafTask = directChildActivity.getTask();
+ final TaskFragment directChildFragment = new TaskFragment(mAtm, new Binder(),
+ true /* createdByOrganizer */, false /* isEmbedded */);
+ nonLeafTask.addChild(directChildFragment, 0);
+
+ assertThat(mSupervisor.mOpaqueContainerHelper.isOpaque(nonLeafTask)).isFalse();
+ }
+
@NonNull
private TaskFragment createChildTaskFragment(@NonNull Task parent,
@WindowConfiguration.WindowingMode int windowingMode,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
index eaffc481098e..1e91bedb5c18 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
@@ -30,7 +28,6 @@ import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
-import android.provider.Settings;
import android.window.DesktopModeFlags;
import androidx.test.filters.SmallTest;
@@ -74,14 +71,12 @@ public class DesktopModeHelperTest {
doReturn(mContext.getContentResolver()).when(mMockContext).getContentResolver();
resetDesktopModeFlagsCache();
resetEnforceDeviceRestriction();
- resetFlagOverride();
}
@After
public void tearDown() throws Exception {
resetDesktopModeFlagsCache();
resetEnforceDeviceRestriction();
- resetFlagOverride();
}
@DisableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
@@ -167,7 +162,8 @@ public class DesktopModeHelperTest {
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
@Test
- public void canEnterDesktopMode_DWFlagEnabled_configDevOptionOn_flagOverrideOn_returnsTrue() {
+ public void canEnterDesktopMode_DWFlagEnabled_configDevOptionOn_flagOverrideOn_returnsTrue()
+ throws Exception {
doReturn(true).when(mMockResources).getBoolean(
eq(R.bool.config_isDesktopModeDevOptionSupported)
);
@@ -177,22 +173,41 @@ public class DesktopModeHelperTest {
}
@Test
- public void isDeviceEligibleForDesktopMode_configDEModeOn_returnsTrue() {
+ public void isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktop_returnsTrue() {
+ doReturn(true).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported));
+ doReturn(true).when(mMockResources)
+ .getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops));
+
+ assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isTrue();
+ }
+
+ @Test
+ public void isDeviceEligibleForDesktopMode_configDEModeOffAndIntDispHostsDesktop_returnsFalse() {
+ doReturn(true).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported));
+ doReturn(false).when(mMockResources)
+ .getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops));
+
+ assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isFalse();
+ }
+
+ @Test
+ public void isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktopOff_returnsFalse() {
+ doReturn(false).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported));
doReturn(true).when(mMockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops));
- assertThat(DesktopModeHelper.isInternalDisplayEligibleToHostDesktops(mMockContext)).isTrue();
+ assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isFalse();
}
@DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
@Test
public void isDeviceEligibleForDesktopMode_supportFlagOff_returnsFalse() {
- assertThat(DesktopModeHelper.isInternalDisplayEligibleToHostDesktops(mMockContext)).isFalse();
+ assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isFalse();
}
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
@Test
public void isDeviceEligibleForDesktopMode_supportFlagOn_returnsFalse() {
- assertThat(DesktopModeHelper.isInternalDisplayEligibleToHostDesktops(mMockContext)).isFalse();
+ assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isFalse();
}
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
@@ -202,7 +217,7 @@ public class DesktopModeHelperTest {
eq(R.bool.config_isDesktopModeDevOptionSupported)
);
- assertThat(DesktopModeHelper.isInternalDisplayEligibleToHostDesktops(mMockContext)).isTrue();
+ assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isTrue();
}
private void resetEnforceDeviceRestriction() throws Exception {
@@ -227,13 +242,10 @@ public class DesktopModeHelperTest {
cachedToggleOverride.set(/* obj= */ null, /* value= */ null);
}
- private void resetFlagOverride() {
- Settings.Global.putString(mContext.getContentResolver(),
- DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, null);
- }
-
- private void setFlagOverride(DesktopModeFlags.ToggleOverride override) {
- Settings.Global.putInt(mContext.getContentResolver(),
- DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, override.getSetting());
+ private void setFlagOverride(DesktopModeFlags.ToggleOverride override) throws Exception {
+ Field cachedToggleOverride = DesktopModeFlags.class.getDeclaredField(
+ "sCachedToggleOverride");
+ cachedToggleOverride.setAccessible(true);
+ cachedToggleOverride.set(/* obj= */ null, /* value= */ override);
}
} \ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 82435b24dad6..6e109a8d4eaf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -164,6 +164,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.function.BooleanSupplier;
/**
* Tests for the {@link DisplayContent} class.
@@ -2674,16 +2675,67 @@ public class DisplayContentTests extends WindowTestsBase {
public void testKeyguardGoingAwayWhileAodShown() {
mDisplayContent.getDisplayPolicy().setAwake(true);
- final WindowState appWin = newWindowBuilder("appWin", TYPE_APPLICATION).setDisplay(
- mDisplayContent).build();
- final ActivityRecord activity = appWin.mActivityRecord;
+ final KeyguardController keyguard = mAtm.mKeyguardController;
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final int displayId = mDisplayContent.getDisplayId();
+
+ final BooleanSupplier keyguardShowing = () -> keyguard.isKeyguardShowing(displayId);
+ final BooleanSupplier keyguardGoingAway = () -> keyguard.isKeyguardGoingAway(displayId);
+ final BooleanSupplier appVisible = activity::isVisibleRequested;
+
+ // Begin locked and in AOD
+ keyguard.setKeyguardShown(displayId, true /* keyguard */, true /* aod */);
+ assertFalse(keyguardGoingAway.getAsBoolean());
+ assertFalse(appVisible.getAsBoolean());
+
+ // Start unlocking from AOD.
+ keyguard.keyguardGoingAway(displayId, 0x0 /* flags */);
+ assertTrue(keyguardGoingAway.getAsBoolean());
+ assertTrue(appVisible.getAsBoolean());
- mAtm.mKeyguardController.setKeyguardShown(appWin.getDisplayId(), true /* keyguardShowing */,
- true /* aodShowing */);
- assertFalse(activity.isVisibleRequested());
+ // Clear AOD. This does *not* clear the going-away status.
+ keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */);
+ assertTrue(keyguardGoingAway.getAsBoolean());
+ assertTrue(appVisible.getAsBoolean());
+
+ // Finish unlock
+ keyguard.setKeyguardShown(displayId, false /* keyguard */, false /* aod */);
+ assertFalse(keyguardGoingAway.getAsBoolean());
+ assertTrue(appVisible.getAsBoolean());
+ }
+
+ @Test
+ public void testKeyguardGoingAwayCanceledWhileAodShown() {
+ mDisplayContent.getDisplayPolicy().setAwake(true);
- mAtm.mKeyguardController.keyguardGoingAway(appWin.getDisplayId(), 0 /* flags */);
- assertTrue(activity.isVisibleRequested());
+ final KeyguardController keyguard = mAtm.mKeyguardController;
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final int displayId = mDisplayContent.getDisplayId();
+
+ final BooleanSupplier keyguardShowing = () -> keyguard.isKeyguardShowing(displayId);
+ final BooleanSupplier keyguardGoingAway = () -> keyguard.isKeyguardGoingAway(displayId);
+ final BooleanSupplier appVisible = activity::isVisibleRequested;
+
+ // Begin locked and in AOD
+ keyguard.setKeyguardShown(displayId, true /* keyguard */, true /* aod */);
+ assertFalse(keyguardGoingAway.getAsBoolean());
+ assertFalse(appVisible.getAsBoolean());
+
+ // Start unlocking from AOD.
+ keyguard.keyguardGoingAway(displayId, 0x0 /* flags */);
+ assertTrue(keyguardGoingAway.getAsBoolean());
+ assertTrue(appVisible.getAsBoolean());
+
+ // Clear AOD. This does *not* clear the going-away status.
+ keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */);
+ assertTrue(keyguardGoingAway.getAsBoolean());
+ assertTrue(appVisible.getAsBoolean());
+
+ // Same API call a second time cancels the unlock, because AOD isn't changing.
+ keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */);
+ assertTrue(keyguardShowing.getAsBoolean());
+ assertFalse(keyguardGoingAway.getAsBoolean());
+ assertFalse(appVisible.getAsBoolean());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
deleted file mode 100644
index 20381ba21758..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm;
-
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_OLD_NONE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
-
-import static junit.framework.Assert.fail;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.RemoteException;
-import android.platform.test.annotations.Presubmit;
-import android.view.IRemoteAnimationFinishedCallback;
-import android.view.IRemoteAnimationRunner;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.server.testutils.OffsettableClock;
-import com.android.server.testutils.TestHandler;
-import com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord;
-import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Build/Install/Run:
- * atest WmTests:RemoteAnimationControllerTest
- */
-@SmallTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class RemoteAnimationControllerTest extends WindowTestsBase {
-
- @Mock
- SurfaceControl mMockLeash;
- @Mock
- SurfaceControl mMockThumbnailLeash;
- @Mock
- Transaction mMockTransaction;
- @Mock
- OnAnimationFinishedCallback mFinishedCallback;
- @Mock
- OnAnimationFinishedCallback mThumbnailFinishedCallback;
- @Mock
- IRemoteAnimationRunner mMockRunner;
- private RemoteAnimationAdapter mAdapter;
- private RemoteAnimationController mController;
- private final OffsettableClock mClock = new OffsettableClock.Stopped();
- private TestHandler mHandler;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- when(mMockRunner.asBinder()).thenReturn(new Binder());
- mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */);
- mAdapter.setCallingPidUid(123, 456);
- runWithScissors(mWm.mH, () -> mHandler = new TestHandler(null, mClock), 0);
- mController = new RemoteAnimationController(mWm, mDisplayContent, mAdapter,
- mHandler, false /*isActivityEmbedding*/);
- mWm.mAnimator.ready();
- }
-
- private WindowState createAppOverlayWindow() {
- final WindowState win = newWindowBuilder("testOverlayWindow",
- TYPE_APPLICATION_OVERLAY).build();
- win.mActivityRecord = null;
- win.mHasSurface = true;
- return win;
- }
-
- @Test
- public void testForwardsShowBackdrop() throws Exception {
- final WindowState win = createTestWindow();
- mDisplayContent.mOpeningApps.add(win.mActivityRecord);
- final WindowState overlayWin = createAppOverlayWindow();
- try {
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null,
- true /* showBackdrop */).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_ACTIVITY_OPEN),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, appsCaptor.getValue().length);
- final RemoteAnimationTarget app = appsCaptor.getValue()[0];
- assertTrue(app.showBackdrop);
- } finally {
- mDisplayContent.mOpeningApps.clear();
- }
- }
-
- @Test
- public void testRun() throws Exception {
- final WindowState win = createTestWindow();
- mDisplayContent.mOpeningApps.add(win.mActivityRecord);
- final WindowState overlayWin = createAppOverlayWindow();
- try {
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_ACTIVITY_OPEN),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, appsCaptor.getValue().length);
- final RemoteAnimationTarget app = appsCaptor.getValue()[0];
- assertEquals(new Point(50, 100), app.position);
- assertEquals(new Rect(50, 100, 150, 150), app.sourceContainerBounds);
- assertEquals(win.mActivityRecord.getPrefixOrderIndex(), app.prefixOrderIndex);
- assertEquals(win.mActivityRecord.getTask().mTaskId, app.taskId);
- assertEquals(mMockLeash, app.leash);
- assertEquals(false, app.isTranslucent);
- verify(mMockTransaction).setPosition(mMockLeash, app.position.x, app.position.y);
- verify(mMockTransaction).setWindowCrop(mMockLeash, 100, 50);
-
- finishedCaptor.getValue().onAnimationFinished();
- verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
- eq(adapter));
- assertEquals(0, nonAppsCaptor.getValue().length);
- } finally {
- mDisplayContent.mOpeningApps.clear();
- }
- }
-
- @Test
- public void testCancel() throws Exception {
- final WindowState win = createTestWindow();
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
-
- adapter.onAnimationCancelled(mMockLeash);
- verify(mMockRunner).onAnimationCancelled();
- }
-
- @Test
- public void testTimeout() throws Exception {
- final WindowState win = createTestWindow();
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
-
- mClock.fastForward(10500);
- mHandler.timeAdvance();
-
- verify(mMockRunner).onAnimationCancelled();
- verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
- eq(adapter));
- }
-
- @Test
- public void testTimeout_scaled() throws Exception {
- try {
- mWm.setAnimationScale(2, 5.0f);
- final WindowState win = createTestWindow();
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord, new Point(50, 100), null, new Rect(50, 100, 150, 150),
- null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
-
- mClock.fastForward(10500);
- mHandler.timeAdvance();
-
- verify(mMockRunner, never()).onAnimationCancelled();
-
- mClock.fastForward(52500);
- mHandler.timeAdvance();
-
- verify(mMockRunner).onAnimationCancelled();
- verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
- eq(adapter));
- } finally {
- mWm.setAnimationScale(2, 1.0f);
- }
- }
-
- @Test
- public void testZeroAnimations() throws Exception {
- mController.goodToGo(TRANSIT_OLD_NONE);
- verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any());
- verify(mMockRunner).onAnimationCancelled();
- }
-
- @Test
- public void testNotReallyStarted() throws Exception {
- final WindowState win = createTestWindow();
- mController.createRemoteAnimationRecord(win.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false);
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any());
- verify(mMockRunner).onAnimationCancelled();
- }
-
- @Test
- public void testOneNotStarted() throws Exception {
- final WindowState win1 = newWindowBuilder("testWin1", TYPE_BASE_APPLICATION).build();
- final WindowState win2 = newWindowBuilder("testWin2", TYPE_BASE_APPLICATION).build();
- mController.createRemoteAnimationRecord(win1.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false);
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win2.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_ACTIVITY_OPEN),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, appsCaptor.getValue().length);
- assertEquals(mMockLeash, appsCaptor.getValue()[0].leash);
- }
-
- @Test
- public void testRemovedBeforeStarted() throws Exception {
- final WindowState win = createTestWindow();
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- win.mActivityRecord.removeImmediately();
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any());
- verify(mMockRunner).onAnimationCancelled();
- verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
- eq(adapter));
- }
-
- @Test
- public void testOpeningTaskWithTopFinishingActivity() {
- final WindowState win = createTestWindow();
- final Task task = win.getTask();
- final ActivityRecord topFinishing = new ActivityBuilder(mAtm).setTask(task).build();
- // Now the task contains:
- // - Activity[1] (top, finishing, no window)
- // - Activity[0] (has window)
- topFinishing.finishing = true;
- spyOn(mDisplayContent.mAppTransition);
- doReturn(mController).when(mDisplayContent.mAppTransition).getRemoteAnimationController();
- task.applyAnimationUnchecked(null /* lp */, true /* enter */, TRANSIT_OLD_TASK_OPEN,
- false /* isVoiceInteraction */, null /* sources */);
- mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- try {
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
- appsCaptor.capture(), any(), any(), any());
- } catch (RemoteException ignored) {
- }
- assertEquals(1, appsCaptor.getValue().length);
- assertEquals(RemoteAnimationTarget.MODE_OPENING, appsCaptor.getValue()[0].mode);
- }
-
- @Test
- public void testChangeToSmallerSize() throws Exception {
- final WindowState win = createTestWindow();
- mDisplayContent.mChangingContainers.add(win.mActivityRecord);
- try {
- final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
- win.mActivityRecord, new Point(50, 100), null, new Rect(50, 100, 150, 150),
- new Rect(0, 0, 200, 200), false);
- assertNotNull(record.mThumbnailAdapter);
- ((AnimationAdapter) record.mAdapter)
- .startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION,
- mFinishedCallback);
- ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
- mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, appsCaptor.getValue().length);
- final RemoteAnimationTarget app = appsCaptor.getValue()[0];
- assertEquals(RemoteAnimationTarget.MODE_CHANGING, app.mode);
- assertEquals(new Point(50, 100), app.position);
- assertEquals(new Rect(50, 100, 150, 150), app.sourceContainerBounds);
- assertEquals(new Rect(0, 0, 200, 200), app.startBounds);
- assertEquals(mMockLeash, app.leash);
- assertEquals(mMockThumbnailLeash, app.startLeash);
- assertEquals(false, app.isTranslucent);
- verify(mMockTransaction).setPosition(
- mMockLeash, app.startBounds.left, app.startBounds.top);
- verify(mMockTransaction).setWindowCrop(
- mMockLeash, app.startBounds.width(), app.startBounds.height());
- verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
- verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
- app.startBounds.height());
-
- finishedCaptor.getValue().onAnimationFinished();
- verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
- eq(record.mAdapter));
- verify(mThumbnailFinishedCallback).onAnimationFinished(
- eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
- } finally {
- mDisplayContent.mChangingContainers.clear();
- }
- }
-
- @Test
- public void testChangeTolargerSize() throws Exception {
- final WindowState win = createTestWindow();
- mDisplayContent.mChangingContainers.add(win.mActivityRecord);
- try {
- final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
- win.mActivityRecord, new Point(0, 0), null, new Rect(0, 0, 200, 200),
- new Rect(50, 100, 150, 150), false);
- assertNotNull(record.mThumbnailAdapter);
- ((AnimationAdapter) record.mAdapter)
- .startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION,
- mFinishedCallback);
- ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
- mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, appsCaptor.getValue().length);
- final RemoteAnimationTarget app = appsCaptor.getValue()[0];
- assertEquals(RemoteAnimationTarget.MODE_CHANGING, app.mode);
- assertEquals(new Point(0, 0), app.position);
- assertEquals(new Rect(0, 0, 200, 200), app.sourceContainerBounds);
- assertEquals(new Rect(50, 100, 150, 150), app.startBounds);
- assertEquals(mMockLeash, app.leash);
- assertEquals(mMockThumbnailLeash, app.startLeash);
- assertEquals(false, app.isTranslucent);
- verify(mMockTransaction).setPosition(
- mMockLeash, app.startBounds.left, app.startBounds.top);
- verify(mMockTransaction).setWindowCrop(
- mMockLeash, app.startBounds.width(), app.startBounds.height());
- verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
- verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
- app.startBounds.height());
-
- finishedCaptor.getValue().onAnimationFinished();
- verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
- eq(record.mAdapter));
- verify(mThumbnailFinishedCallback).onAnimationFinished(
- eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
- } finally {
- mDisplayContent.mChangingContainers.clear();
- }
- }
-
- @Test
- public void testChangeToDifferentPosition() throws Exception {
- final WindowState win = createTestWindow();
- mDisplayContent.mChangingContainers.add(win.mActivityRecord);
- try {
- final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
- win.mActivityRecord, new Point(100, 100), null, new Rect(150, 150, 400, 400),
- new Rect(50, 100, 150, 150), false);
- assertNotNull(record.mThumbnailAdapter);
- ((AnimationAdapter) record.mAdapter)
- .startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION,
- mFinishedCallback);
- ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
- mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, appsCaptor.getValue().length);
- final RemoteAnimationTarget app = appsCaptor.getValue()[0];
- assertEquals(RemoteAnimationTarget.MODE_CHANGING, app.mode);
- assertEquals(new Point(100, 100), app.position);
- assertEquals(new Rect(150, 150, 400, 400), app.sourceContainerBounds);
- assertEquals(new Rect(50, 100, 150, 150), app.startBounds);
- assertEquals(mMockLeash, app.leash);
- assertEquals(mMockThumbnailLeash, app.startLeash);
- assertEquals(false, app.isTranslucent);
- verify(mMockTransaction).setPosition(
- mMockLeash, app.position.x + app.startBounds.left - app.screenSpaceBounds.left,
- app.position.y + app.startBounds.top - app.screenSpaceBounds.top);
- verify(mMockTransaction).setWindowCrop(
- mMockLeash, app.startBounds.width(), app.startBounds.height());
- verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
- verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
- app.startBounds.height());
-
- finishedCaptor.getValue().onAnimationFinished();
- verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
- eq(record.mAdapter));
- verify(mThumbnailFinishedCallback).onAnimationFinished(
- eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
- } finally {
- mDisplayContent.mChangingContainers.clear();
- }
- }
-
- @Test
- public void testWallpaperIncluded_expectTarget() throws Exception {
- final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
- true, mDisplayContent, true /* ownerCanManageAppTokens */);
- spyOn(mDisplayContent.mWallpaperController);
- doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
- final WindowState win = createTestWindow();
- mDisplayContent.mOpeningApps.add(win.mActivityRecord);
- try {
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_ACTIVITY_OPEN),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, wallpapersCaptor.getValue().length);
- } finally {
- mDisplayContent.mOpeningApps.clear();
- }
- }
-
- @Test
- public void testWallpaperAnimatorCanceled_expectAnimationKeepsRunning() throws Exception {
- final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
- true, mDisplayContent, true /* ownerCanManageAppTokens */);
- spyOn(mDisplayContent.mWallpaperController);
- doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
- final WindowState win = createTestWindow();
- mDisplayContent.mOpeningApps.add(win.mActivityRecord);
- try {
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord,
- new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAPpsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_ACTIVITY_OPEN),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAPpsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, wallpapersCaptor.getValue().length);
-
- // Cancel the wallpaper window animator and ensure the runner is not canceled
- wallpaperWindowToken.cancelAnimation();
- verify(mMockRunner, never()).onAnimationCancelled();
- } finally {
- mDisplayContent.mOpeningApps.clear();
- }
- }
-
- @Test
- public void testNonAppIncluded_keygaurdGoingAway() throws Exception {
- final WindowState win = createTestWindow();
- mDisplayContent.mOpeningApps.add(win.mActivityRecord);
- // Add overlay window hidden by the keyguard.
- final WindowState overlayWin = createAppOverlayWindow();
- overlayWin.hide(false /* doAnimation */, false /* requestAnim */);
- try {
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord, new Point(50, 100), null,
- new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_KEYGUARD_GOING_AWAY);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_KEYGUARD_GOING_AWAY),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, appsCaptor.getValue().length);
- final RemoteAnimationTarget app = appsCaptor.getValue()[0];
- assertEquals(new Point(50, 100), app.position);
- assertEquals(new Rect(50, 100, 150, 150), app.sourceContainerBounds);
- assertEquals(win.mActivityRecord.getPrefixOrderIndex(), app.prefixOrderIndex);
- assertEquals(win.mActivityRecord.getTask().mTaskId, app.taskId);
- assertEquals(mMockLeash, app.leash);
- assertEquals(false, app.isTranslucent);
- verify(mMockTransaction).setPosition(mMockLeash, app.position.x, app.position.y);
- verify(mMockTransaction).setWindowCrop(mMockLeash, 100, 50);
-
- finishedCaptor.getValue().onAnimationFinished();
- verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
- eq(adapter));
- assertEquals(1, nonAppsCaptor.getValue().length);
- } finally {
- mDisplayContent.mOpeningApps.clear();
- }
- }
-
- @Test
- public void testNonAppIncluded_keygaurdGoingAwayToWallpaper() throws Exception {
- final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
- true, mDisplayContent, true /* ownerCanManageAppTokens */);
- spyOn(mDisplayContent.mWallpaperController);
- doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
- final WindowState win = createTestWindow();
- mDisplayContent.mOpeningApps.add(win.mActivityRecord);
- // Add overlay window hidden by the keyguard.
- final WindowState overlayWin = createAppOverlayWindow();
- overlayWin.hide(false /* doAnimation */, false /* requestAnim */);
- try {
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord, new Point(50, 100), null,
- new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
- waitUntilWindowAnimatorIdle();
- final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER),
- appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
- finishedCaptor.capture());
- assertEquals(1, wallpapersCaptor.getValue().length);
- assertEquals(1, nonAppsCaptor.getValue().length);
- } finally {
- mDisplayContent.mOpeningApps.clear();
- }
- }
-
- @Test
- public void testNonAppTarget_sendNavBar() throws Exception {
- final int transit = TRANSIT_OLD_TASK_OPEN;
- final AnimationAdapter adapter = setupForNonAppTargetNavBar(transit, true);
-
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
- ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
- verify(mMockRunner).onAnimationStart(eq(transit), any(), any(),
- nonAppsCaptor.capture(), finishedCaptor.capture());
- boolean containNavTarget = false;
- for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
- if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
- containNavTarget = true;
- break;
- }
- }
- assertTrue(containNavTarget);
- assertEquals(1, mController.mPendingNonAppAnimations.size());
- final NonAppWindowAnimationAdapter nonAppAdapter =
- mController.mPendingNonAppAnimations.get(0);
- spyOn(nonAppAdapter.getLeashFinishedCallback());
-
- finishedCaptor.getValue().onAnimationFinished();
- verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
- eq(adapter));
- verify(nonAppAdapter.getLeashFinishedCallback())
- .onAnimationFinished(nonAppAdapter.getLastAnimationType(), nonAppAdapter);
- }
-
- @Test
- public void testNonAppTarget_notSendNavBar_notAttachToApp() throws Exception {
- final int transit = TRANSIT_OLD_TASK_OPEN;
- setupForNonAppTargetNavBar(transit, false);
-
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- verify(mMockRunner).onAnimationStart(eq(transit),
- any(), any(), nonAppsCaptor.capture(), any());
- for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
- if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
- fail("Non-app animation target must not contain navbar");
- }
- }
- }
-
- @Test
- public void testNonAppTarget_notSendNavBar_controlledByFadeRotation() throws Exception {
- final AsyncRotationController mockController =
- mock(AsyncRotationController.class);
- doReturn(mockController).when(mDisplayContent).getAsyncRotationController();
- final int transit = TRANSIT_OLD_TASK_OPEN;
- setupForNonAppTargetNavBar(transit, true);
-
- final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
- ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
- verify(mMockRunner).onAnimationStart(eq(transit),
- any(), any(), nonAppsCaptor.capture(), any());
- for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
- if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
- fail("Non-app animation target must not contain navbar");
- }
- }
- }
-
- private AnimationAdapter setupForNonAppTargetNavBar(int transit, boolean shouldAttachNavBar) {
- final WindowState win = createTestWindow();
- mDisplayContent.mOpeningApps.add(win.mActivityRecord);
- final WindowState navBar = newWindowBuilder("NavigationBar", TYPE_NAVIGATION_BAR).build();
- mDisplayContent.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
- final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
- spyOn(policy);
- doReturn(shouldAttachNavBar).when(policy).shouldAttachNavBarToAppDuringTransition();
-
- final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord, new Point(50, 100), null,
- new Rect(50, 100, 150, 150), null, false).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
- mFinishedCallback);
- mController.goodToGo(transit);
- waitUntilWindowAnimatorIdle();
- return adapter;
- }
-
- private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
- verify(binder, atLeast(0)).asBinder();
- verifyNoMoreInteractions(binder);
- }
-
- private WindowState createTestWindow() {
- return newWindowBuilder("testWin", TYPE_BASE_APPLICATION).build();
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 95bca2b17efb..1dc32b00acba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -4486,6 +4486,49 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ @EnableFlags(Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS)
+ @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
+ public void testInFreeform_boundsSandboxedToAppBounds() {
+ allowDesktopMode();
+ final int dw = 2800;
+ final int dh = 1400;
+ final int notchHeight = 100;
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, dw, dh)
+ .setNotch(notchHeight)
+ .build();
+ setUpApp(display);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ mTask.mDisplayContent.getDefaultTaskDisplayArea()
+ .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+ mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ Rect appBounds = new Rect(0, 0, 1000, 500);
+ Rect bounds = new Rect(0, 0, 1000, 600);
+ mTask.getWindowConfiguration().setAppBounds(appBounds);
+ mTask.getWindowConfiguration().setBounds(bounds);
+ mActivity.onConfigurationChanged(mTask.getConfiguration());
+
+ // Bounds are sandboxed to appBounds in freeform.
+ assertDownScaled();
+ assertEquals(mActivity.getWindowConfiguration().getAppBounds(),
+ mActivity.getWindowConfiguration().getBounds());
+
+ // Exit freeform.
+ mTask.mDisplayContent.getDefaultTaskDisplayArea()
+ .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+ mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mTask.getWindowConfiguration().setBounds(new Rect(0, 0, dw, dh));
+ mActivity.onConfigurationChanged(mTask.getConfiguration());
+ assertFitted();
+ appBounds = mActivity.getWindowConfiguration().getAppBounds();
+ bounds = mActivity.getWindowConfiguration().getBounds();
+ // Bounds are not sandboxed to appBounds.
+ assertNotEquals(appBounds, bounds);
+ assertEquals(notchHeight, appBounds.top - bounds.top);
+ }
+
+
+ @Test
@EnableFlags(Flags.FLAG_IGNORE_ASPECT_RATIO_RESTRICTIONS_FOR_RESIZEABLE_FREEFORM_ACTIVITIES)
public void testUserAspectRatioOverridesNotAppliedToResizeableFreeformActivity() {
final TaskBuilder taskBuilder =
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 546ecc6e38a5..ab76ae8e378a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -29,14 +29,14 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_PRIVILEGED_REORDER_TO_BOTTOM_OF_TASK;
+import static android.window.TaskFragmentOperation.OP_TYPE_PRIVILEGED_REORDER_TO_TOP_OF_TASK;
+import static android.window.TaskFragmentOperation.OP_TYPE_PRIVILEGED_SET_CAN_AFFECT_SYSTEM_UI_FLAGS;
import static android.window.TaskFragmentOperation.OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE;
-import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_BOTTOM_OF_TASK;
import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT;
-import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_TOP_OF_TASK;
import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
-import static android.window.TaskFragmentOperation.OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_DIM_ON_TASK;
import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
@@ -1821,7 +1821,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Reorder TaskFragment to bottom
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
- OP_TYPE_REORDER_TO_BOTTOM_OF_TASK).build();
+ OP_TYPE_PRIVILEGED_REORDER_TO_BOTTOM_OF_TASK).build();
mTransaction.addTaskFragmentOperation(tf1.getFragmentToken(), operation);
assertApplyTransactionAllowed(mTransaction);
@@ -1858,7 +1858,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Reorder TaskFragment to top
final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
- OP_TYPE_REORDER_TO_TOP_OF_TASK).build();
+ OP_TYPE_PRIVILEGED_REORDER_TO_TOP_OF_TASK).build();
mTransaction.addTaskFragmentOperation(tf0.getFragmentToken(), operation);
assertApplyTransactionAllowed(mTransaction);
@@ -1903,13 +1903,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
@Test
public void testApplyTransaction_reorderToBottomOfTask_failsIfNotSystemOrganizer() {
testApplyTransaction_reorder_failsIfNotSystemOrganizer_common(
- OP_TYPE_REORDER_TO_BOTTOM_OF_TASK);
+ OP_TYPE_PRIVILEGED_REORDER_TO_BOTTOM_OF_TASK);
}
@Test
public void testApplyTransaction_reorderToTopOfTask_failsIfNotSystemOrganizer() {
testApplyTransaction_reorder_failsIfNotSystemOrganizer_common(
- OP_TYPE_REORDER_TO_TOP_OF_TASK);
+ OP_TYPE_PRIVILEGED_REORDER_TO_TOP_OF_TASK);
}
@Test
@@ -1922,7 +1922,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Setting the flag to false.
TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
- OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS).setBooleanValue(false).build();
+ OP_TYPE_PRIVILEGED_SET_CAN_AFFECT_SYSTEM_UI_FLAGS).setBooleanValue(false).build();
mTransaction.addTaskFragmentOperation(tf.getFragmentToken(), operation);
assertApplyTransactionAllowed(mTransaction);
@@ -1931,7 +1931,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Setting the flag back to true.
operation = new TaskFragmentOperation.Builder(
- OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS).setBooleanValue(true).build();
+ OP_TYPE_PRIVILEGED_SET_CAN_AFFECT_SYSTEM_UI_FLAGS).setBooleanValue(true).build();
mTransaction.addTaskFragmentOperation(tf.getFragmentToken(), operation);
assertApplyTransactionAllowed(mTransaction);
@@ -1945,7 +1945,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final TaskFragment tf = createTaskFragment(task);
TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
- OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS).setBooleanValue(false).build();
+ OP_TYPE_PRIVILEGED_SET_CAN_AFFECT_SYSTEM_UI_FLAGS).setBooleanValue(false).build();
mTransaction
.addTaskFragmentOperation(tf.getFragmentToken(), operation)
.setErrorCallbackToken(mErrorToken);
@@ -1955,7 +1955,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// The pending event will be dispatched on the handler (from requestTraversal).
waitHandlerIdle(mWm.mAnimationHandler);
- assertTaskFragmentErrorTransaction(OP_TYPE_SET_CAN_AFFECT_SYSTEM_UI_FLAGS,
+ assertTaskFragmentErrorTransaction(OP_TYPE_PRIVILEGED_SET_CAN_AFFECT_SYSTEM_UI_FLAGS,
SecurityException.class);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
deleted file mode 100644
index 849072e133ae..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-
-import android.hardware.HardwareBuffer;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.server.testutils.StubTransaction;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test class for {@link TaskSnapshotSurface}.
- *
- * Build/Install/Run:
- * atest WmTests:WindowContainerThumbnailTest
- *
- */
-@SmallTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class WindowContainerThumbnailTest extends WindowTestsBase {
- private WindowContainerThumbnail buildThumbnail() {
- final HardwareBuffer buffer = HardwareBuffer.create(1, 1, HardwareBuffer.RGBA_8888,
- 1, HardwareBuffer.USAGE_CPU_READ_RARELY);
- final ActivityRecord mockAr = mock(ActivityRecord.class);
- when(mockAr.getPendingTransaction()).thenReturn(new StubTransaction());
- when(mockAr.makeChildSurface(any())).thenReturn(new MockSurfaceControlBuilder());
- when(mockAr.makeSurface()).thenReturn(new MockSurfaceControlBuilder());
- return new WindowContainerThumbnail(new StubTransaction(), mockAr, buffer,
- mock(SurfaceAnimator.class));
- }
-
- @Test
- public void testDestroy_nullsSurface() {
- final WindowContainerThumbnail t = buildThumbnail();
- assertNotNull(t.getSurfaceControl());
- t.destroy();
- assertNull(t.getSurfaceControl());
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index a718c06cc2fa..59ee2f5c8e9f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -1281,6 +1281,7 @@ public class WindowStateTests extends WindowTestsBase {
// Simulate app plays closing transition to app2.
app.mActivityRecord.commitVisibility(false, false);
+ mDisplayContent.computeImeTarget(true /* updateImeTarget */);
assertTrue(app.mActivityRecord.mLastImeShown);
// Verify the IME insets is visible on app, but not for app2 during app task switching.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
index 12b744546f5e..9367941e32a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
@@ -18,12 +18,16 @@ package com.android.server.wm;
import static android.tools.traces.Utils.busyWaitForDataSourceRegistration;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -34,11 +38,15 @@ import android.platform.test.annotations.Presubmit;
import android.tools.ScenarioBuilder;
import android.tools.traces.io.ResultWriter;
import android.tools.traces.monitors.PerfettoTraceMonitor;
+import android.util.Log;
import android.view.Choreographer;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
+import androidx.test.uiautomator.UiDevice;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -51,14 +59,15 @@ import java.io.IOException;
/**
* Test class for {@link WindowTracingPerfetto}.
*/
+@FlakyTest(bugId = 372558379)
@SmallTest
@Presubmit
public class WindowTracingPerfettoTest {
private static final String TEST_DATA_SOURCE_NAME = "android.windowmanager.test";
private static WindowManagerService sWmMock;
- private static Choreographer sChoreographer;
private static WindowTracing sWindowTracing;
+ private static Boolean sIsDataSourceRegisteredSuccessfully;
private PerfettoTraceMonitor mTraceMonitor;
@@ -66,19 +75,39 @@ public class WindowTracingPerfettoTest {
public static void setUpOnce() throws Exception {
sWmMock = Mockito.mock(WindowManagerService.class);
Mockito.doNothing().when(sWmMock).dumpDebugLocked(Mockito.any(), Mockito.anyInt());
- sChoreographer = Mockito.mock(Choreographer.class);
- sWindowTracing = new WindowTracingPerfetto(sWmMock, sChoreographer,
+ sWindowTracing = new WindowTracingPerfetto(sWmMock, Mockito.mock(Choreographer.class),
new WindowManagerGlobalLock(), TEST_DATA_SOURCE_NAME);
- busyWaitForDataSourceRegistration(TEST_DATA_SOURCE_NAME);
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ sWmMock = null;
+ sWindowTracing = null;
}
@Before
public void setUp() throws IOException {
- Mockito.clearInvocations(sWmMock);
+ if (sIsDataSourceRegisteredSuccessfully != null) {
+ assumeTrue("Failed to register data source", sIsDataSourceRegisteredSuccessfully);
+ return;
+ }
+ try {
+ busyWaitForDataSourceRegistration(TEST_DATA_SOURCE_NAME);
+ sIsDataSourceRegisteredSuccessfully = true;
+ } catch (Exception e) {
+ sIsDataSourceRegisteredSuccessfully = false;
+ final String perfettoStatus = UiDevice.getInstance(getInstrumentation())
+ .executeShellCommand("perfetto --query");
+ Log.e(WindowTracingPerfettoTest.class.getSimpleName(),
+ "Failed to register data source: " + perfettoStatus);
+ // Only fail once. The rest tests will be skipped by assumeTrue.
+ fail("Failed to register data source");
+ }
}
@After
public void tearDown() throws IOException {
+ Mockito.clearInvocations(sWmMock);
stopTracing();
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0b3d720bf52a..1a932859b750 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -10207,6 +10207,17 @@ public class CarrierConfigManager {
"carrier_supported_satellite_notification_hysteresis_sec_int";
/**
+ * Satellite notification display restriction reset time in seconds.
+ *
+ * The device shows a notification when it connects to a satellite. If the user interacts
+ * with the notification, it won't be shown again immediately. Instead, the notification
+ * will only reappear after below key mentioned amount of time has passed.
+ */
+ @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
+ public static final String KEY_SATELLITE_CONNECTED_NOTIFICATION_THROTTLE_MILLIS_INT =
+ "satellite_connected_notification_throttle_millis_int";
+
+ /**
* An integer key holds the timeout duration in seconds used to determine whether to exit
* carrier-roaming NB-IOT satellite mode.
*
@@ -11428,6 +11439,10 @@ public class CarrierConfigManager {
sDefaults.putInt(KEY_CARRIER_ROAMING_NTN_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_INT,
SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911);
sDefaults.putInt(KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT, 180);
+ if (Flags.starlinkDataBugfix()) {
+ sDefaults.putLong(KEY_SATELLITE_CONNECTED_NOTIFICATION_THROTTLE_MILLIS_INT,
+ TimeUnit.DAYS.toMillis(7));
+ }
sDefaults.putInt(KEY_SATELLITE_ROAMING_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT, 30);
sDefaults.putInt(KEY_SATELLITE_ROAMING_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT, 180);
sDefaults.putInt(KEY_SATELLITE_ROAMING_ESOS_INACTIVITY_TIMEOUT_SEC_INT, 600);
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index b7b209b78300..100690dcbb65 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -821,6 +821,25 @@ public final class SatelliteManager {
"android.telephony.METADATA_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT";
/**
+ * A boolean value indicating whether application is optimized to utilize low bandwidth
+ * satellite data.
+ * The applications that are optimized for low bandwidth satellite data should set this
+ * property to {@code true} in the manifest to indicate to platform about the same.
+ * {@code
+ * <application>
+ * <meta-data
+ * android:name="android.telephony.PROPERTY_SATELLITE_DATA_OPTIMIZED"
+ * android:value="true"/>
+ * </application>
+ * }
+ * <p>
+ * When {@code true}, satellite data optimized network is available for applications.
+ */
+ @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
+ public static final String PROPERTY_SATELLITE_DATA_OPTIMIZED =
+ "android.telephony.PROPERTY_SATELLITE_DATA_OPTIMIZED";
+
+ /**
* Registers a {@link SatelliteStateChangeListener} to receive callbacks when the satellite
* state may have changed.
*
@@ -3840,6 +3859,35 @@ public final class SatelliteManager {
}
}
+ /**
+ * Get list of application packages name that are optimized for low bandwidth satellite data.
+ *
+ * @return List of application packages name with data optimized network property.
+ *
+ * {@link #PROPERTY_SATELLITE_DATA_OPTIMIZED}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
+ public @NonNull List<String> getSatelliteDataOptimizedApps() {
+ List<String> appsNames = new ArrayList<>();
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ appsNames = telephony.getSatelliteDataOptimizedApps();
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("getSatelliteDataOptimizedApps() RemoteException:" + ex);
+ ex.rethrowAsRuntimeException();
+ }
+
+ return appsNames;
+ }
+
@Nullable
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 08c003027c5b..1c6652daf498 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3596,4 +3596,15 @@ interface ITelephony {
* @hide
*/
int getCarrierIdFromIdentifier(in CarrierIdentifier carrierIdentifier);
+
+
+ /**
+ * Get list of applications that are optimized for low bandwidth satellite data.
+ *
+ * @return List of Application Name with data optimized network property.
+ * {@link #PROPERTY_SATELLITE_DATA_OPTIMIZED}
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ List<String> getSatelliteDataOptimizedApps();
}
diff --git a/tests/AppJankTest/res/values/strings.xml b/tests/AppJankTest/res/values/strings.xml
new file mode 100644
index 000000000000..ab2d18fa9d53
--- /dev/null
+++ b/tests/AppJankTest/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="continue_test">Continue Test</string>
+</resources> \ No newline at end of file
diff --git a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
index fe9f63615757..3498974b348e 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
@@ -209,7 +209,8 @@ public class IntegrationTests {
JankTrackerActivity.class);
resumeJankTracker.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
mEmptyActivity.startActivity(resumeJankTracker);
- mDevice.wait(Until.findObject(By.text("Edit Text")), WAIT_FOR_TIMEOUT_MS);
+ mDevice.wait(Until.findObject(By.text(mEmptyActivity.getString(R.string.continue_test))),
+ WAIT_FOR_TIMEOUT_MS);
assertTrue(jankTracker.shouldTrack());
}
diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java
index 80ab6ad3e587..686758200853 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java
@@ -18,15 +18,41 @@ package android.app.jank.tests;
import android.app.Activity;
import android.os.Bundle;
+import android.widget.EditText;
public class JankTrackerActivity extends Activity {
+ private static final int CONTINUE_TEST_DELAY_MS = 4000;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.jank_tracker_activity_layout);
}
+
+ /**
+ * In IntegrationTests#jankTrackingResumed_whenActivityBecomesVisibleAgain this activity is
+ * placed into the background and then resumed via an intent. The test waits until the
+ * `continue_test` string is visible on the screen before validating that Jank tracking has
+ * resumed.
+ *
+ * <p>The 4 second delay allows JankTracker to re-register its callbacks and start receiving
+ * JankData before the test proceeds.
+ */
+ @Override
+ protected void onResume() {
+ super.onResume();
+ getActivityThread().getHandler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ EditText editTextView = findViewById(R.id.edit_text);
+ if (editTextView != null) {
+ editTextView.setText(R.string.continue_test);
+ }
+ }
+ }, CONTINUE_TEST_DELAY_MS);
+ }
}
diff --git a/tests/AttestationVerificationTest/src/com/android/server/security/CertificateRevocationStatusManagerTest.java b/tests/AttestationVerificationTest/src/com/android/server/security/CertificateRevocationStatusManagerTest.java
index c38517ace5e6..586bb76388f6 100644
--- a/tests/AttestationVerificationTest/src/com/android/server/security/CertificateRevocationStatusManagerTest.java
+++ b/tests/AttestationVerificationTest/src/com/android/server/security/CertificateRevocationStatusManagerTest.java
@@ -277,6 +277,72 @@ public class CertificateRevocationStatusManagerTest {
}
}
+ @Test
+ public void checkRevocationStatus_allCertificatesRecentlyChecked_doesNotFetchRemoteCrl()
+ throws Exception {
+ copyFromAssetToFile(
+ REVOCATION_LIST_WITHOUT_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile);
+ mCertificateRevocationStatusManager =
+ new CertificateRevocationStatusManager(
+ mContext, mRevocationListUrl, mRevocationStatusFile, false);
+ mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1);
+ // indirectly verifies the remote list is not fetched by simulating a remote revocation
+ copyFromAssetToFile(
+ REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile);
+
+ // no exception
+ mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1);
+ }
+
+ @Test
+ public void checkRevocationStatus_allCertificatesBarelyRecentlyChecked_doesNotFetchRemoteCrl()
+ throws Exception {
+ copyFromAssetToFile(
+ REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile);
+ mCertificateRevocationStatusManager =
+ new CertificateRevocationStatusManager(
+ mContext, mRevocationListUrl, mRevocationStatusFile, false);
+ Map<String, LocalDateTime> lastCheckedDates = new HashMap<>();
+ LocalDateTime barelyRecently =
+ LocalDateTime.now()
+ .minusHours(
+ CertificateRevocationStatusManager.NUM_HOURS_BEFORE_NEXT_CHECK - 1);
+ for (X509Certificate certificate : mCertificates1) {
+ lastCheckedDates.put(getSerialNumber(certificate), barelyRecently);
+ }
+ mCertificateRevocationStatusManager.storeLastRevocationCheckData(lastCheckedDates);
+
+ // Indirectly verify the remote CRL is not checked by checking there is no exception despite
+ // a certificate being revoked. This test differs from the next only in the lastCheckedDate,
+ // one before the NUM_HOURS_BEFORE_NEXT_CHECK cutoff and one after
+ mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1);
+ }
+
+ @Test
+ public void checkRevocationStatus_certificatesRevokedAfterCheck_throwsException()
+ throws Exception {
+ copyFromAssetToFile(
+ REVOCATION_LIST_WITH_CERTIFICATES_USED_IN_THIS_TEST, mRevocationListFile);
+ mCertificateRevocationStatusManager =
+ new CertificateRevocationStatusManager(
+ mContext, mRevocationListUrl, mRevocationStatusFile, false);
+ Map<String, LocalDateTime> lastCheckedDates = new HashMap<>();
+ // To save network use, we do not check the remote CRL if all the certificates are recently
+ // checked, so we set the lastCheckDate to some time not recent.
+ LocalDateTime notRecently =
+ LocalDateTime.now()
+ .minusHours(
+ CertificateRevocationStatusManager.NUM_HOURS_BEFORE_NEXT_CHECK + 1);
+ for (X509Certificate certificate : mCertificates1) {
+ lastCheckedDates.put(getSerialNumber(certificate), notRecently);
+ }
+ mCertificateRevocationStatusManager.storeLastRevocationCheckData(lastCheckedDates);
+
+ assertThrows(
+ CertPathValidatorException.class,
+ () -> mCertificateRevocationStatusManager.checkRevocationStatus(mCertificates1));
+ }
+
private List<X509Certificate> getCertificateChain(String fileName) throws Exception {
Collection<? extends Certificate> certificates =
mFactory.generateCertificates(mContext.getResources().getAssets().open(fileName));
diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
index b22e42d1ab89..a2f6f0051116 100644
--- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
@@ -333,7 +333,7 @@ class InputManagerServiceTests {
fun testKeyActivenessNotifyEventsLifecycle() {
service.systemRunning()
- fakePermissionEnforcer.grant(android.Manifest.permission.LISTEN_FOR_KEY_ACTIVITY);
+ fakePermissionEnforcer.grant(android.Manifest.permission.LISTEN_FOR_KEY_ACTIVITY)
val inputManager = context.getSystemService(InputManager::class.java)
@@ -358,6 +358,34 @@ class InputManagerServiceTests {
verifyNoMoreInteractions(listener)
}
+ @Test
+ fun testKeyEventsForwardedToFocusedWindow_whenWmAllows() {
+ service.systemRunning()
+ overrideSendActionKeyEventsToFocusedWindow(
+ /* hasPermission = */false,
+ /* hasPrivateFlag = */false
+ )
+ whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(0)
+
+ val event = KeyEvent( /* downTime= */0, /* eventTime= */0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_SPACE, /* repeat= */0, KeyEvent.META_CTRL_ON)
+ assertEquals(0, service.interceptKeyBeforeDispatching(null, event, 0))
+ }
+
+ @Test
+ fun testKeyEventsNotForwardedToFocusedWindow_whenWmConsumes() {
+ service.systemRunning()
+ overrideSendActionKeyEventsToFocusedWindow(
+ /* hasPermission = */false,
+ /* hasPrivateFlag = */false
+ )
+ whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(-1)
+
+ val event = KeyEvent( /* downTime= */0, /* eventTime= */0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_SPACE, /* repeat= */0, KeyEvent.META_CTRL_ON)
+ assertEquals(-1, service.interceptKeyBeforeDispatching(null, event, 0))
+ }
+
private class AutoClosingVirtualDisplays(val displays: List<VirtualDisplay>) : AutoCloseable {
operator fun get(i: Int): VirtualDisplay = displays[i]
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
index a3d03a8278ed..3be725101252 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
@@ -38,6 +38,8 @@ import android.tools.traces.io.ResultReader;
import android.tools.traces.io.ResultWriter;
import android.tools.traces.monitors.PerfettoTraceMonitor;
+import com.android.internal.protolog.IProtoLogConfigurationService.RegisterClientArgs;
+
import com.google.common.truth.Truth;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -152,10 +154,9 @@ public class ProtoLogConfigurationServiceTest {
public void canRegisterClientWithGroupsOnly() throws RemoteException {
final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
- final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
- new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
- .GroupConfig(TEST_GROUP, true));
+ final RegisterClientArgs args = new RegisterClientArgs();
+ args.groups = new String[] { TEST_GROUP };
+ args.groupsDefaultLogcatStatus = new boolean[] { true };
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
@@ -167,11 +168,11 @@ public class ProtoLogConfigurationServiceTest {
throws RemoteException, InvalidProtocolBufferException {
final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
- final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
- new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
- .GroupConfig(TEST_GROUP, true))
- .setViewerConfigFile(mViewerConfigFile.getAbsolutePath());
+ final RegisterClientArgs args = new RegisterClientArgs();
+ args.groups = new String[] { TEST_GROUP };
+ args.groupsDefaultLogcatStatus = new boolean[] { true };
+ args.viewerConfigFile = mViewerConfigFile.getAbsolutePath();
+
service.registerClient(mMockClient, args);
service.registerClient(mSecondMockClient, args);
@@ -204,11 +205,11 @@ public class ProtoLogConfigurationServiceTest {
Mockito.mock(ProtoLogConfigurationServiceImpl.ViewerConfigFileTracer.class);
final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl(tracer);
- final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
- new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
- .GroupConfig(TEST_GROUP, true))
- .setViewerConfigFile(mViewerConfigFile.getAbsolutePath());
+ final RegisterClientArgs args = new RegisterClientArgs();
+ args.groups = new String[] { TEST_GROUP };
+ args.groupsDefaultLogcatStatus = new boolean[] { true };
+ args.viewerConfigFile = mViewerConfigFile.getAbsolutePath();
+
service.registerClient(mMockClient, args);
service.registerClient(mSecondMockClient, args);
@@ -227,9 +228,9 @@ public class ProtoLogConfigurationServiceTest {
public void sendEnableLoggingToLogcatToClient() throws RemoteException {
final var service = new ProtoLogConfigurationServiceImpl();
- final var args = new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
- .GroupConfig(TEST_GROUP, false));
+ final RegisterClientArgs args = new RegisterClientArgs();
+ args.groups = new String[] { TEST_GROUP };
+ args.groupsDefaultLogcatStatus = new boolean[] { false };
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
@@ -244,10 +245,9 @@ public class ProtoLogConfigurationServiceTest {
public void sendDisableLoggingToLogcatToClient() throws RemoteException {
final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
- final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
- new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
- .GroupConfig(TEST_GROUP, true));
+ final RegisterClientArgs args = new RegisterClientArgs();
+ args.groups = new String[] { TEST_GROUP };
+ args.groupsDefaultLogcatStatus = new boolean[] { true };
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
@@ -262,10 +262,10 @@ public class ProtoLogConfigurationServiceTest {
public void doNotSendLoggingToLogcatToClientWithoutRegisteredGroup() throws RemoteException {
final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
- final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
- new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
- .GroupConfig(TEST_GROUP, false));
+ final RegisterClientArgs args = new RegisterClientArgs();
+ args.groups = new String[] { TEST_GROUP };
+ args.groupsDefaultLogcatStatus = new boolean[] { false };
+
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
@@ -283,10 +283,10 @@ public class ProtoLogConfigurationServiceTest {
service.enableProtoLogToLogcat(TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
- final ProtoLogConfigurationServiceImpl.RegisterClientArgs args =
- new ProtoLogConfigurationServiceImpl.RegisterClientArgs()
- .setGroups(new ProtoLogConfigurationServiceImpl.RegisterClientArgs
- .GroupConfig(TEST_GROUP, false));
+ final RegisterClientArgs args = new RegisterClientArgs();
+ args.groups = new String[] { TEST_GROUP };
+ args.groupsDefaultLogcatStatus = new boolean[] { false };
+
service.registerClient(mMockClient, args);
Mockito.verify(mMockClient).toggleLogcat(eq(true),
diff --git a/tests/testables/tests/src/android/animation/AnimatorTestRuleToolkitTest.kt b/tests/testables/tests/src/android/animation/AnimatorTestRuleToolkitTest.kt
index 993c3fed9d59..2eb8ba1be811 100644
--- a/tests/testables/tests/src/android/animation/AnimatorTestRuleToolkitTest.kt
+++ b/tests/testables/tests/src/android/animation/AnimatorTestRuleToolkitTest.kt
@@ -16,6 +16,7 @@
package android.animation
+import android.content.pm.PackageManager
import android.graphics.Color
import android.platform.test.annotations.MotionTest
import android.view.ViewGroup
@@ -23,11 +24,14 @@ import android.widget.FrameLayout
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.internal.dynamicanimation.animation.DynamicAnimation
import com.android.internal.dynamicanimation.animation.SpringAnimation
import com.android.internal.dynamicanimation.animation.SpringForce
import kotlinx.coroutines.test.TestScope
+import org.junit.Assume.assumeFalse
+import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -65,6 +69,16 @@ class AnimatorTestRuleToolkitTest {
bitmapDiffer = screenshotRule,
)
+ @Before
+ fun setUp() {
+ // Do not run on Automotive.
+ assumeFalse(
+ InstrumentationRegistry.getInstrumentation().context.packageManager.hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE
+ )
+ )
+ }
+
@Test
fun recordFilmstrip_withAnimator() {
val animatedBox = createScene()
@@ -188,12 +202,7 @@ class AnimatorTestRuleToolkitTest {
null
}
return motionRule.recordMotion(
- AnimatorRuleRecordingSpec(
- container,
- motionControl,
- sampleIntervalMs,
- visualCapture,
- ) {
+ AnimatorRuleRecordingSpec(container, motionControl, sampleIntervalMs, visualCapture) {
feature(ViewFeatureCaptures.alpha, "alpha")
}
)
diff --git a/tests/utils/testutils/java/android/os/test/TestLooper.java b/tests/utils/testutils/java/android/os/test/TestLooper.java
index 83d22d923c78..4d379e45a81a 100644
--- a/tests/utils/testutils/java/android/os/test/TestLooper.java
+++ b/tests/utils/testutils/java/android/os/test/TestLooper.java
@@ -18,18 +18,24 @@ package android.os.test;
import static org.junit.Assert.assertTrue;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.os.SystemClock;
+import android.os.TestLooperManager;
import android.util.Log;
+import androidx.test.platform.app.InstrumentationRegistry;
+
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.ArrayDeque;
+import java.util.Queue;
import java.util.concurrent.Executor;
/**
@@ -44,7 +50,9 @@ import java.util.concurrent.Executor;
* The Robolectric class also allows advancing time.
*/
public class TestLooper {
- protected final Looper mLooper;
+ private final Looper mLooper;
+ private final TestLooperManager mTestLooperManager;
+ private final Clock mClock;
private static final Constructor<Looper> LOOPER_CONSTRUCTOR;
private static final Field THREAD_LOCAL_LOOPER_FIELD;
@@ -54,24 +62,46 @@ public class TestLooper {
private static final Method MESSAGE_MARK_IN_USE_METHOD;
private static final String TAG = "TestLooper";
- private final Clock mClock;
-
private AutoDispatchThread mAutoDispatchThread;
+ /**
+ * Baklava introduces new {@link TestLooperManager} APIs that we can use instead of reflection.
+ */
+ private static boolean isAtLeastBaklava() {
+ Method[] methods = TestLooperManager.class.getMethods();
+ for (Method method : methods) {
+ if (method.getName().equals("peekWhen")) {
+ return true;
+ }
+ }
+ return false;
+ // TODO(shayba): delete the above, uncomment the below.
+ // SDK_INT has not yet ramped to Baklava in all 25Q2 builds.
+ // return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA;
+ }
+
static {
try {
LOOPER_CONSTRUCTOR = Looper.class.getDeclaredConstructor(Boolean.TYPE);
LOOPER_CONSTRUCTOR.setAccessible(true);
THREAD_LOCAL_LOOPER_FIELD = Looper.class.getDeclaredField("sThreadLocal");
THREAD_LOCAL_LOOPER_FIELD.setAccessible(true);
- MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages");
- MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true);
- MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next");
- MESSAGE_NEXT_FIELD.setAccessible(true);
- MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when");
- MESSAGE_WHEN_FIELD.setAccessible(true);
- MESSAGE_MARK_IN_USE_METHOD = Message.class.getDeclaredMethod("markInUse");
- MESSAGE_MARK_IN_USE_METHOD.setAccessible(true);
+
+ if (isAtLeastBaklava()) {
+ MESSAGE_QUEUE_MESSAGES_FIELD = null;
+ MESSAGE_NEXT_FIELD = null;
+ MESSAGE_WHEN_FIELD = null;
+ MESSAGE_MARK_IN_USE_METHOD = null;
+ } else {
+ MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages");
+ MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true);
+ MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next");
+ MESSAGE_NEXT_FIELD.setAccessible(true);
+ MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when");
+ MESSAGE_WHEN_FIELD.setAccessible(true);
+ MESSAGE_MARK_IN_USE_METHOD = Message.class.getDeclaredMethod("markInUse");
+ MESSAGE_MARK_IN_USE_METHOD.setAccessible(true);
+ }
} catch (NoSuchFieldException | NoSuchMethodException e) {
throw new RuntimeException("Failed to initialize TestLooper", e);
}
@@ -106,6 +136,13 @@ public class TestLooper {
throw new RuntimeException("Reflection error constructing or accessing looper", e);
}
+ if (isAtLeastBaklava()) {
+ mTestLooperManager =
+ InstrumentationRegistry.getInstrumentation().acquireLooperManager(mLooper);
+ } else {
+ mTestLooperManager = null;
+ }
+
mClock = clock;
}
@@ -117,19 +154,61 @@ public class TestLooper {
return new HandlerExecutor(new Handler(getLooper()));
}
- private Message getMessageLinkedList() {
+ private Message getMessageLinkedListLegacy() {
try {
MessageQueue queue = mLooper.getQueue();
return (Message) MESSAGE_QUEUE_MESSAGES_FIELD.get(queue);
} catch (IllegalAccessException e) {
throw new RuntimeException("Access failed in TestLooper: get - MessageQueue.mMessages",
- e);
+ e);
}
}
public void moveTimeForward(long milliSeconds) {
+ if (isAtLeastBaklava()) {
+ moveTimeForwardBaklava(milliSeconds);
+ } else {
+ moveTimeForwardLegacy(milliSeconds);
+ }
+ }
+
+ private void moveTimeForwardBaklava(long milliSeconds) {
+ // Drain all Messages from the queue.
+ Queue<Message> messages = new ArrayDeque<>();
+ while (true) {
+ Message message = mTestLooperManager.poll();
+ if (message == null) {
+ break;
+ }
+ messages.add(message);
+ }
+
+ // Repost all Messages back to the queue with a new time.
+ while (true) {
+ Message message = messages.poll();
+ if (message == null) {
+ break;
+ }
+
+ // Ugly trick to reset the Message's "in use" flag.
+ // This is needed because the Message cannot be re-enqueued if it's
+ // marked in use.
+ message.copyFrom(message);
+
+ // Adjust the Message's delivery time.
+ long newWhen = message.getWhen() - milliSeconds;
+ if (newWhen < 0) {
+ newWhen = 0;
+ }
+
+ // Send the Message back to its Handler to be re-enqueued.
+ message.getTarget().sendMessageAtTime(message, newWhen);
+ }
+ }
+
+ private void moveTimeForwardLegacy(long milliSeconds) {
try {
- Message msg = getMessageLinkedList();
+ Message msg = getMessageLinkedListLegacy();
while (msg != null) {
long updatedWhen = msg.getWhen() - milliSeconds;
if (updatedWhen < 0) {
@@ -147,12 +226,12 @@ public class TestLooper {
return mClock.uptimeMillis();
}
- private Message messageQueueNext() {
+ private Message messageQueueNextLegacy() {
try {
long now = currentTime();
Message prevMsg = null;
- Message msg = getMessageLinkedList();
+ Message msg = getMessageLinkedListLegacy();
if (msg != null && msg.getTarget() == null) {
// Stalled by a barrier. Find the next asynchronous message in
// the queue.
@@ -185,18 +264,46 @@ public class TestLooper {
/**
* @return true if there are pending messages in the message queue
*/
- public synchronized boolean isIdle() {
- Message messageList = getMessageLinkedList();
+ public boolean isIdle() {
+ if (isAtLeastBaklava()) {
+ return isIdleBaklava();
+ } else {
+ return isIdleLegacy();
+ }
+ }
+
+ private boolean isIdleBaklava() {
+ Long when = mTestLooperManager.peekWhen();
+ return when != null && currentTime() >= when;
+ }
+ private synchronized boolean isIdleLegacy() {
+ Message messageList = getMessageLinkedListLegacy();
return messageList != null && currentTime() >= messageList.getWhen();
}
/**
* @return the next message in the Looper's message queue or null if there is none
*/
- public synchronized Message nextMessage() {
+ public Message nextMessage() {
+ if (isAtLeastBaklava()) {
+ return nextMessageBaklava();
+ } else {
+ return nextMessageLegacy();
+ }
+ }
+
+ private Message nextMessageBaklava() {
+ if (isIdle()) {
+ return mTestLooperManager.poll();
+ } else {
+ return null;
+ }
+ }
+
+ private synchronized Message nextMessageLegacy() {
if (isIdle()) {
- return messageQueueNext();
+ return messageQueueNextLegacy();
} else {
return null;
}
@@ -206,9 +313,26 @@ public class TestLooper {
* Dispatch the next message in the queue
* Asserts that there is a message in the queue
*/
- public synchronized void dispatchNext() {
+ public void dispatchNext() {
+ if (isAtLeastBaklava()) {
+ dispatchNextBaklava();
+ } else {
+ dispatchNextLegacy();
+ }
+ }
+
+ private void dispatchNextBaklava() {
+ assertTrue(isIdle());
+ Message msg = mTestLooperManager.poll();
+ if (msg == null) {
+ return;
+ }
+ msg.getTarget().dispatchMessage(msg);
+ }
+
+ private synchronized void dispatchNextLegacy() {
assertTrue(isIdle());
- Message msg = messageQueueNext();
+ Message msg = messageQueueNextLegacy();
if (msg == null) {
return;
}
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
index 51a300bff7ea..661ed07a5669 100644
--- a/tests/vcn/Android.bp
+++ b/tests/vcn/Android.bp
@@ -16,13 +16,19 @@ android_test {
name: "FrameworksVcnTests",
// For access hidden connectivity methods in tests
defaults: ["framework-connectivity-test-defaults"],
+
+ // TODO: b/374174952 Use 36 after Android B finalization
+ min_sdk_version: "35",
+
srcs: [
"java/**/*.java",
"java/**/*.kt",
],
platform_apis: true,
- test_suites: ["device-tests"],
- certificate: "platform",
+ test_suites: [
+ "general-tests",
+ "mts-tethering",
+ ],
static_libs: [
"android.net.vcn.flags-aconfig-java-export",
"androidx.test.rules",
diff --git a/tests/vcn/AndroidManifest.xml b/tests/vcn/AndroidManifest.xml
index a8f657c89f76..08effbd1f7cf 100644
--- a/tests/vcn/AndroidManifest.xml
+++ b/tests/vcn/AndroidManifest.xml
@@ -16,8 +16,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.tests.vcn">
- <uses-sdk android:minSdkVersion="33"
- android:targetSdkVersion="33"/>
+ <!-- TODO: b/374174952 Use 36 after Android B finalization -->
+ <uses-sdk android:minSdkVersion="35" android:targetSdkVersion="35" />
+
<application>
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/vcn/AndroidTest.xml b/tests/vcn/AndroidTest.xml
index dc521fd7bcd9..9c8362f36cb2 100644
--- a/tests/vcn/AndroidTest.xml
+++ b/tests/vcn/AndroidTest.xml
@@ -14,12 +14,20 @@
limitations under the License.
-->
<configuration description="Runs VCN Tests.">
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
<option name="test-file-name" value="FrameworksVcnTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-tag" value="FrameworksVcnTests" />
+
+ <!-- Run tests in MTS only if the Tethering Mainline module is installed. -->
+ <object type="module_controller"
+ class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.tethering" />
+ </object>
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.tests.vcn" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java
index 156961312323..0fa11ae1fe7d 100644
--- a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java
@@ -23,11 +23,24 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.HashSet;
import java.util.Set;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase {
private static final Set<String> ALLOWED_PLMN_IDS = new HashSet<>();
private static final Set<Integer> ALLOWED_CARRIER_IDS = new HashSet<>();
diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
index 73a0a6183cb6..fa97de0aff45 100644
--- a/tests/vcn/java/android/net/vcn/VcnConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
@@ -29,11 +29,14 @@ import static org.mockito.Mockito.mock;
import android.annotation.NonNull;
import android.content.Context;
+import android.os.Build;
import android.os.Parcel;
import android.util.ArraySet;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
@@ -42,7 +45,10 @@ import org.junit.runner.RunWith;
import java.util.Collections;
import java.util.Set;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnConfigTest {
private static final String TEST_PACKAGE_NAME = VcnConfigTest.class.getPackage().getName();
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 59dc68900100..990cc74caf6c 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -34,10 +34,13 @@ import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
import android.net.vcn.persistablebundleutils.IkeSessionParamsUtilsTest;
import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,7 +52,10 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnGatewayConnectionConfigTest {
// Public for use in VcnGatewayConnectionTest
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 8461de6d877b..1739fbc0fa6d 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -38,16 +38,28 @@ import android.net.NetworkCapabilities;
import android.net.vcn.VcnManager.VcnStatusCallback;
import android.net.vcn.VcnManager.VcnStatusCallbackBinder;
import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
+import android.os.Build;
import android.os.ParcelUuid;
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.net.UnknownHostException;
import java.util.UUID;
import java.util.concurrent.Executor;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class VcnManagerTest {
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
private static final String GATEWAY_CONNECTION_NAME = "gatewayConnectionName";
diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
index 7bc9970629a6..52952eb3f2cc 100644
--- a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
@@ -30,12 +30,24 @@ import static org.junit.Assert.fail;
import android.net.NetworkCapabilities;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
+import android.os.Build;
import android.os.Parcel;
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Arrays;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class VcnTransportInfoTest {
private static final int SUB_ID = 1;
private static final int NETWORK_ID = 5;
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
index a674425efea3..c82d2003dbf6 100644
--- a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
@@ -22,9 +22,21 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import android.net.NetworkCapabilities;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
+import org.junit.runner.RunWith;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class VcnUnderlyingNetworkPolicyTest {
private static final VcnUnderlyingNetworkPolicy DEFAULT_NETWORK_POLICY =
new VcnUnderlyingNetworkPolicy(
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java
index 2110d6ee7c86..22361cc71f12 100644
--- a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java
@@ -22,14 +22,20 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.net.TelephonyNetworkSpecifier;
+import android.os.Build;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnUnderlyingNetworkSpecifierTest {
private static final int[] TEST_SUB_IDS = new int[] {1, 2, 3, 5};
diff --git a/tests/vcn/java/android/net/vcn/VcnUtilsTest.java b/tests/vcn/java/android/net/vcn/VcnUtilsTest.java
index 3ce6c8f9386d..fb040d8f9b91 100644
--- a/tests/vcn/java/android/net/vcn/VcnUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnUtilsTest.java
@@ -30,13 +30,25 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.TelephonyNetworkSpecifier;
import android.net.wifi.WifiInfo;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.Collections;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class VcnUtilsTest {
private static final int SUB_ID = 1;
diff --git a/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java
index 4063178e005d..2c072e1cbc88 100644
--- a/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java
@@ -22,10 +22,23 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Set;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class VcnWifiUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase {
private static final String SSID = "TestWifi";
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java
index bc8e9d3200b6..01e9ac2ac3cf 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java
@@ -21,11 +21,14 @@ import static android.telephony.TelephonyManager.APPTYPE_USIM;
import static org.junit.Assert.assertEquals;
import android.net.eap.EapSessionConfig;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,7 +38,10 @@ import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class EapSessionConfigUtilsTest {
private static final byte[] EAP_ID = "test@android.net".getBytes(StandardCharsets.US_ASCII);
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java
index 4f3930f9b5af..821e5a6c94cb 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java
@@ -25,10 +25,13 @@ import android.net.ipsec.ike.IkeIpv4AddrIdentification;
import android.net.ipsec.ike.IkeIpv6AddrIdentification;
import android.net.ipsec.ike.IkeKeyIdIdentification;
import android.net.ipsec.ike.IkeRfc822AddrIdentification;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,7 +42,10 @@ import java.net.InetAddress;
import javax.security.auth.x500.X500Principal;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class IkeIdentificationUtilsTest {
private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeIdentification id) {
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
index 9f7d2390938f..7200aee1c012 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
@@ -29,14 +29,16 @@ import android.net.InetAddresses;
import android.net.eap.EapSessionConfig;
import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeSessionParams;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.org.bouncycastle.util.io.pem.PemObject;
import com.android.internal.org.bouncycastle.util.io.pem.PemReader;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,7 +54,10 @@ import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.util.concurrent.TimeUnit;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class IkeSessionParamsUtilsTest {
// Public for use in VcnGatewayConnectionConfigTest, EncryptedTunnelParamsUtilsTest
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
index 28cf38a2a583..957e785d70c0 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
@@ -20,17 +20,23 @@ import static org.junit.Assert.assertEquals;
import android.net.InetAddresses;
import android.net.ipsec.ike.IkeTrafficSelector;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class IkeTrafficSelectorUtilsTest {
private static final int START_PORT = 16;
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
index 664044a9e7d4..1e8f5ff2dc07 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
@@ -21,15 +21,21 @@ import static org.junit.Assert.assertEquals;
import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.IkeSaProposal;
import android.net.ipsec.ike.SaProposal;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class SaProposalUtilsTest {
/** Package private so that IkeSessionParamsUtilsTest can use it */
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java
index f9dc9eb4d5ae..7d17724112ec 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java
@@ -20,14 +20,20 @@ import static org.junit.Assert.assertEquals;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.os.Build;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class TunnelConnectionParamsUtilsTest {
// Public for use in VcnGatewayConnectionConfigTest
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
index e0b5f0ef0381..3d7348a79b8c 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
@@ -25,10 +25,13 @@ import android.net.InetAddresses;
import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.IkeTrafficSelector;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,7 +40,10 @@ import java.net.Inet4Address;
import java.net.Inet6Address;
import java.util.concurrent.TimeUnit;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class TunnelModeChildSessionParamsUtilsTest {
// Package private for use in EncryptedTunnelParamsUtilsTest
diff --git a/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java b/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java
index 47638b002f37..99c7aa72146b 100644
--- a/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java
@@ -33,9 +33,12 @@ import static org.junit.Assert.assertTrue;
import static java.util.Collections.emptyList;
import android.net.ipsec.ike.ChildSaProposal;
+import android.os.Build;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -43,7 +46,10 @@ import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.List;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class MtuUtilsTest {
private void verifyUnderlyingMtuZero(boolean isIpv4) {
diff --git a/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java b/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java
index c84e60086b37..f7786af840ee 100644
--- a/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java
@@ -21,10 +21,13 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,7 +38,10 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class PersistableBundleUtilsTest {
private static final String TEST_KEY = "testKey";
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 26a2a0636792..a97f9a837bab 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -79,6 +79,7 @@ import android.net.vcn.VcnManager;
import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.net.vcn.util.PersistableBundleUtils;
import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
+import android.os.Build;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
@@ -93,7 +94,6 @@ import android.telephony.TelephonyManager;
import android.util.ArraySet;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.VcnManagementService.VcnCallback;
import com.android.server.VcnManagementService.VcnStatusCallbackInfo;
@@ -101,6 +101,8 @@ import com.android.server.vcn.TelephonySubscriptionTracker;
import com.android.server.vcn.Vcn;
import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Rule;
@@ -117,8 +119,10 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
-/** Tests for {@link VcnManagementService}. */
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnManagementServiceTest {
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 77f82f0d8cf4..6276be27fbf5 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -54,6 +54,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.vcn.VcnManager;
+import android.os.Build;
import android.os.Handler;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
@@ -69,9 +70,10 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.modules.utils.HandlerExecutor;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
@@ -87,8 +89,10 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
-/** Tests for TelephonySubscriptionTracker */
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class TelephonySubscriptionTrackerTest {
private static final String PACKAGE_NAME =
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 74db6a5211a0..6608dda95a4b 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -70,16 +70,18 @@ import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.net.vcn.VcnManager.VcnErrorCode;
import android.net.vcn.VcnTransportInfo;
import android.net.vcn.util.MtuUtils;
+import android.os.Build;
import android.os.PersistableBundle;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
@@ -94,8 +96,10 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
-/** Tests for VcnGatewayConnection.ConnectedState */
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
private static final int PARALLEL_SA_COUNT = 4;
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index 3c70759a2fa6..f6123d29f35a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -26,17 +26,22 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.net.ipsec.ike.IkeSessionParams;
+import android.os.Build;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-/** Tests for VcnGatewayConnection.ConnectingState */
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectionTestBase {
private VcnIkeSession mIkeSession;
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index f3eb82f46de7..7cfaf5be5111 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -30,16 +30,21 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.net.IpSecManager;
+import android.os.Build;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-/** Tests for VcnGatewayConnection.DisconnectedState */
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase {
@Before
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
index 78aefad9f8ff..9132d830c54e 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -23,15 +23,21 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.os.Build;
+
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-/** Tests for VcnGatewayConnection.DisconnectedState */
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnectionTestBase {
@Before
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
index 6568cdd44377..d5ef4e028709 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -27,15 +27,21 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.os.Build;
+
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-/** Tests for VcnGatewayConnection.RetryTimeoutState */
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase {
private long mFirstRetryInterval;
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index b9fe76a24d20..5283322682ee 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -61,15 +61,17 @@ import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.net.vcn.VcnManager;
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
+import android.os.Build;
import android.os.ParcelUuid;
import android.os.Process;
import android.telephony.SubscriptionInfo;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
@@ -87,8 +89,10 @@ import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
-/** Tests for TelephonySubscriptionTracker */
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
private static final int TEST_UID = Process.myUid() + 1;
diff --git a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
index e9026e22b6b2..2b92428918db 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
@@ -29,12 +29,14 @@ import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkRequest;
+import android.os.Build;
import android.os.test.TestLooper;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
@@ -44,8 +46,10 @@ import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
import java.util.List;
-/** Tests for TelephonySubscriptionTracker */
-@RunWith(AndroidJUnit4.class)
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@SmallTest
public class VcnNetworkProviderTest {
private static final int TEST_SCORE_UNSATISFIED = 0;
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index 6d269686e42f..bd4aeba761da 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -49,20 +49,26 @@ import android.net.Uri;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.os.Build;
import android.os.ParcelUuid;
import android.os.test.TestLooper;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
+import androidx.test.filters.SmallTest;
+
import com.android.server.VcnManagementService.VcnCallback;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
import com.android.server.vcn.Vcn.VcnUserMobileDataStateListener;
import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
@@ -73,6 +79,11 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class VcnTest {
private static final String PKG_NAME = VcnTest.class.getPackage().getName();
private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
index c11b6bb3435d..53a36d3e4d6a 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
@@ -44,16 +44,22 @@ import static org.mockito.Mockito.when;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.net.IpSecTransformState;
+import android.os.Build;
import android.os.OutcomeReceiver;
import android.os.PowerManager;
+import androidx.test.filters.SmallTest;
+
import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculationResult;
import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculator;
import com.android.server.vcn.routeselection.NetworkMetricMonitor.IpSecTransformWrapper;
import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
@@ -63,6 +69,11 @@ import java.util.Arrays;
import java.util.BitSet;
import java.util.concurrent.TimeUnit;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase {
private static final String TAG = IpSecPacketLossDetectorTest.class.getSimpleName();
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
index 4f34f9f8f74c..a9c637f7c943 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
@@ -42,16 +42,28 @@ import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnManager;
import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.net.vcn.VcnWifiUnderlyingNetworkTemplate;
+import android.os.Build;
import android.os.PersistableBundle;
import android.util.ArraySet;
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class NetworkPriorityClassifierTest extends NetworkEvaluationTestBase {
private UnderlyingNetworkRecord mWifiNetworkRecord;
private UnderlyingNetworkRecord mCellNetworkRecord;
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
index e540932d0e1f..99c508c139ec 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
@@ -58,6 +58,7 @@ import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
import android.net.vcn.VcnCellUnderlyingNetworkTemplateTest;
import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.net.vcn.VcnUnderlyingNetworkTemplate;
+import android.os.Build;
import android.os.ParcelUuid;
import android.os.test.TestLooper;
import android.telephony.CarrierConfigManager;
@@ -65,6 +66,8 @@ import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
+import androidx.test.filters.SmallTest;
+
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider;
@@ -73,9 +76,12 @@ import com.android.server.vcn.routeselection.UnderlyingNetworkController.Network
import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback;
import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener;
import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
@@ -89,6 +95,11 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class UnderlyingNetworkControllerTest {
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
private static final int INITIAL_SUB_ID_1 = 1;
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
index a315b0690ec5..27c1bc105bde 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
@@ -38,19 +38,30 @@ import static org.mockito.Mockito.when;
import android.net.IpSecTransform;
import android.net.vcn.VcnGatewayConnectionConfig;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback;
import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.Dependencies;
import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import java.util.concurrent.TimeUnit;
+// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on
+// Android B/B+
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+@SmallTest
public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase {
private static final int PENALTY_TIMEOUT_MIN = 10;
private static final long PENALTY_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(PENALTY_TIMEOUT_MIN);
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index e24fe07f959b..9ef8b7dc9947 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -349,20 +349,22 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions&
value->value->Accept(&body_printer);
printer->Undent();
}
- printer->Println("Flag disabled values:");
- for (const auto& value : entry.flag_disabled_values) {
- printer->Print("(");
- printer->Print(value->config.to_string());
- printer->Print(") ");
- value->value->Accept(&headline_printer);
- if (options.show_sources && !value->value->GetSource().path.empty()) {
- printer->Print(" src=");
- printer->Print(value->value->GetSource().to_string());
+ if (!entry.flag_disabled_values.empty()) {
+ printer->Println("Flag disabled values:");
+ for (const auto& value : entry.flag_disabled_values) {
+ printer->Print("(");
+ printer->Print(value->config.to_string());
+ printer->Print(") ");
+ value->value->Accept(&headline_printer);
+ if (options.show_sources && !value->value->GetSource().path.empty()) {
+ printer->Print(" src=");
+ printer->Print(value->value->GetSource().to_string());
+ }
+ printer->Println();
+ printer->Indent();
+ value->value->Accept(&body_printer);
+ printer->Undent();
}
- printer->Println();
- printer->Indent();
- value->value->Accept(&body_printer);
- printer->Undent();
}
printer->Undent();
}
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index d3750a6100d3..b2b9179d4ffe 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -29,7 +29,8 @@ namespace aapt {
class DiffContext : public IAaptContext {
public:
- DiffContext() : name_mangler_({}), symbol_table_(&name_mangler_) {
+ explicit DiffContext(bool ignore_id_shift)
+ : ignore_id_shift(ignore_id_shift), name_mangler_({}), symbol_table_(&name_mangler_) {
}
PackageType GetPackageType() override {
@@ -71,6 +72,8 @@ class DiffContext : public IAaptContext {
return empty;
}
+ const bool ignore_id_shift;
+
private:
std::string empty_;
StdErrDiagnostics diagnostics_;
@@ -79,7 +82,7 @@ class DiffContext : public IAaptContext {
};
static void EmitDiffLine(const android::Source& source, StringPiece message) {
- std::cerr << source << ": " << message << "\n";
+ std::cout << source << ": " << message << "\n";
}
static bool IsSymbolVisibilityDifferent(const Visibility& vis_a, const Visibility& vis_b) {
@@ -95,8 +98,27 @@ static bool IsIdDiff(const Visibility::Level& level_a, const std::optional<Id>&
return false;
}
+class ZeroingIdVisitor : public DescendingValueVisitor {
+ public:
+ using DescendingValueVisitor::Visit;
+
+ void Visit(Reference* ref) override {
+ if (ref->name) {
+ ref->id.reset();
+ }
+ }
+};
+
+static std::unique_ptr<Value> CloneAndClearIds(const Value* value, LoadedApk* apk) {
+ CloningValueTransformer cloner(&apk->GetResourceTable()->string_pool);
+ auto res = value->Transform(cloner);
+ ZeroingIdVisitor visitor;
+ res->Accept(&visitor);
+ return res;
+}
+
static bool EmitResourceConfigValueDiff(
- IAaptContext* context, LoadedApk* apk_a, const ResourceTablePackageView& pkg_a,
+ DiffContext* context, LoadedApk* apk_a, const ResourceTablePackageView& pkg_a,
const ResourceTableTypeView& type_a, const ResourceTableEntryView& entry_a,
const ResourceConfigValue* config_value_a, LoadedApk* apk_b,
const ResourceTablePackageView& pkg_b, const ResourceTableTypeView& type_b,
@@ -104,6 +126,14 @@ static bool EmitResourceConfigValueDiff(
Value* value_a = config_value_a->value.get();
Value* value_b = config_value_b->value.get();
if (!value_a->Equals(value_b)) {
+ if (context->ignore_id_shift) {
+ // Check if the values are only different because of their IDs
+ auto cleared_a = CloneAndClearIds(value_a, apk_a);
+ auto cleared_b = CloneAndClearIds(value_b, apk_b);
+ if (cleared_a->Equals(cleared_b.get())) {
+ return false;
+ }
+ }
std::stringstream str_stream;
str_stream << "value " << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
<< " config='" << config_value_a->config << "' does not match:\n";
@@ -116,7 +146,7 @@ static bool EmitResourceConfigValueDiff(
return false;
}
-static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
+static bool EmitResourceEntryDiff(DiffContext* context, LoadedApk* apk_a,
const ResourceTablePackageView& pkg_a,
const ResourceTableTypeView& type_a,
const ResourceTableEntryView& entry_a, LoadedApk* apk_b,
@@ -180,90 +210,96 @@ static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
return diff;
}
-static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
+static const ResourceTableEntryView* findEntry(const ResourceTableTypeView& type,
+ const ResourceTableEntryView& entry) {
+ auto it = std::ranges::find_if(type.entries, [&](const ResourceTableEntryView& other_entry) {
+ return other_entry.name == entry.name;
+ });
+ return it != std::end(type.entries) ? &*it : nullptr;
+}
+
+static bool EmitResourceTypeDiff(DiffContext* context, LoadedApk* apk_a,
const ResourceTablePackageView& pkg_a,
const ResourceTableTypeView& type_a, LoadedApk* apk_b,
const ResourceTablePackageView& pkg_b,
const ResourceTableTypeView& type_b) {
bool diff = false;
- auto entry_a_iter = type_a.entries.begin();
- auto entry_b_iter = type_b.entries.begin();
- while (entry_a_iter != type_a.entries.end() || entry_b_iter != type_b.entries.end()) {
- if (entry_b_iter == type_b.entries.end()) {
+ std::unordered_set<const ResourceTableEntryView*> found_b_entries;
+ for (auto&& entry_a : type_a.entries) {
+ auto entry_b_iter = findEntry(type_b, entry_a);
+ if (!entry_b_iter) {
// Type A contains a type that type B does not have.
std::stringstream str_stream;
- str_stream << "missing " << pkg_a.name << ":" << type_a.named_type << "/"
- << entry_a_iter->name;
+ str_stream << "missing " << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name;
EmitDiffLine(apk_a->GetSource(), str_stream.str());
diff = true;
- } else if (entry_a_iter == type_a.entries.end()) {
- // Type B contains a type that type A does not have.
+ continue;
+ }
+ const auto& entry_b = *entry_b_iter;
+ found_b_entries.insert(&entry_b);
+ if (IsSymbolVisibilityDifferent(entry_a.visibility, entry_b.visibility)) {
std::stringstream str_stream;
- str_stream << "new entry " << pkg_b.name << ":" << type_b.named_type << "/"
- << entry_b_iter->name;
+ str_stream << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
+ << " has different visibility (";
+ if (entry_b.visibility.staged_api) {
+ str_stream << "STAGED ";
+ }
+ if (entry_b.visibility.level == Visibility::Level::kPublic) {
+ str_stream << "PUBLIC";
+ } else {
+ str_stream << "PRIVATE";
+ }
+ str_stream << " vs ";
+ if (entry_a.visibility.staged_api) {
+ str_stream << "STAGED ";
+ }
+ if (entry_a.visibility.level == Visibility::Level::kPublic) {
+ str_stream << "PUBLIC";
+ } else {
+ str_stream << "PRIVATE";
+ }
+ str_stream << ")";
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
- } else {
- const auto& entry_a = *entry_a_iter;
- const auto& entry_b = *entry_b_iter;
- if (IsSymbolVisibilityDifferent(entry_a.visibility, entry_b.visibility)) {
- std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
- << " has different visibility (";
- if (entry_b.visibility.staged_api) {
- str_stream << "STAGED ";
- }
- if (entry_b.visibility.level == Visibility::Level::kPublic) {
- str_stream << "PUBLIC";
- } else {
- str_stream << "PRIVATE";
- }
- str_stream << " vs ";
- if (entry_a.visibility.staged_api) {
- str_stream << "STAGED ";
- }
- if (entry_a.visibility.level == Visibility::Level::kPublic) {
- str_stream << "PUBLIC";
- } else {
- str_stream << "PRIVATE";
- }
- str_stream << ")";
- EmitDiffLine(apk_b->GetSource(), str_stream.str());
- diff = true;
- } else if (IsIdDiff(entry_a.visibility.level, entry_a.id, entry_b.visibility.level,
- entry_b.id)) {
- std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
- << " has different public ID (";
- if (entry_b.id) {
- str_stream << "0x" << std::hex << entry_b.id.value();
- } else {
- str_stream << "none";
- }
- str_stream << " vs ";
- if (entry_a.id) {
- str_stream << "0x " << std::hex << entry_a.id.value();
- } else {
- str_stream << "none";
- }
- str_stream << ")";
- EmitDiffLine(apk_b->GetSource(), str_stream.str());
- diff = true;
+ } else if (!context->ignore_id_shift && IsIdDiff(entry_a.visibility.level, entry_a.id,
+ entry_b.visibility.level, entry_b.id)) {
+ std::stringstream str_stream;
+ str_stream << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
+ << " has different public ID (";
+ if (entry_b.id) {
+ str_stream << "0x" << std::hex << entry_b.id.value();
+ } else {
+ str_stream << "none";
}
- diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a, apk_b, pkg_b, type_b,
- entry_b);
- }
- if (entry_a_iter != type_a.entries.end()) {
- ++entry_a_iter;
+ str_stream << " vs ";
+ if (entry_a.id) {
+ str_stream << "0x " << std::hex << entry_a.id.value();
+ } else {
+ str_stream << "none";
+ }
+ str_stream << ")";
+ EmitDiffLine(apk_b->GetSource(), str_stream.str());
+ diff = true;
}
- if (entry_b_iter != type_b.entries.end()) {
- ++entry_b_iter;
+ diff |= EmitResourceEntryDiff(context, apk_a, pkg_a, type_a, entry_a, apk_b, pkg_b, type_b,
+ entry_b);
+ }
+ if (found_b_entries.size() < type_b.entries.size()) {
+ diff = true;
+ for (auto&& entry_b : type_b.entries) {
+ if (found_b_entries.contains(&entry_b)) {
+ continue;
+ }
+ // Type B contains a type that type A does not have.
+ std::stringstream str_stream;
+ str_stream << "new entry " << pkg_b.name << ":" << type_b.named_type << "/" << entry_b.name;
+ EmitDiffLine(apk_b->GetSource(), str_stream.str());
}
}
return diff;
}
-static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
+static bool EmitResourcePackageDiff(DiffContext* context, LoadedApk* apk_a,
const ResourceTablePackageView& pkg_a, LoadedApk* apk_b,
const ResourceTablePackageView& pkg_b) {
bool diff = false;
@@ -302,7 +338,8 @@ static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
str_stream << ")";
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
- } else if (IsIdDiff(type_a.visibility_level, type_a.id, type_b.visibility_level, type_b.id)) {
+ } else if (!context->ignore_id_shift &&
+ IsIdDiff(type_a.visibility_level, type_a.id, type_b.visibility_level, type_b.id)) {
std::stringstream str_stream;
str_stream << pkg_a.name << ":" << type_a.named_type << " has different public ID (";
if (type_b.id) {
@@ -332,7 +369,7 @@ static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
return diff;
}
-static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
+static bool EmitResourceTableDiff(DiffContext* context, LoadedApk* apk_a, LoadedApk* apk_b) {
const auto table_a = apk_a->GetResourceTable()->GetPartitionedView();
const auto table_b = apk_b->GetResourceTable()->GetPartitionedView();
@@ -355,7 +392,7 @@ static bool EmitResourceTableDiff(IAaptContext* context, LoadedApk* apk_a, Loade
} else {
const auto& package_a = *package_a_iter;
const auto& package_b = *package_b_iter;
- if (package_a.id != package_b.id) {
+ if (package_a.id != package_b.id && !context->ignore_id_shift) {
std::stringstream str_stream;
str_stream << "package '" << package_a.name << "' has different id (";
if (package_b.id) {
@@ -405,7 +442,7 @@ static void ZeroOutAppReferences(ResourceTable* table) {
}
int DiffCommand::Action(const std::vector<std::string>& args) {
- DiffContext context;
+ DiffContext context(ignore_id_shift_);
if (args.size() != 2u) {
std::cerr << "must have two apks as arguments.\n\n";
diff --git a/tools/aapt2/cmd/Diff.h b/tools/aapt2/cmd/Diff.h
index c38888863be9..32e394416880 100644
--- a/tools/aapt2/cmd/Diff.h
+++ b/tools/aapt2/cmd/Diff.h
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-#ifndef AAPT2_DIFF_H
-#define AAPT2_DIFF_H
-
+#pragma once
#include "Command.h"
namespace aapt {
@@ -25,11 +23,16 @@ class DiffCommand : public Command {
public:
explicit DiffCommand() : Command("diff") {
SetDescription("Prints the differences in resources of two apks.");
+ AddOptionalSwitch("--ignore-id-shift",
+ "Match the resources when their IDs shift, e.g. because of the added\n"
+ "or deleted entries.",
+ &ignore_id_shift_);
}
int Action(const std::vector<std::string>& args) override;
-};
-}// namespace aapt
+ private:
+ bool ignore_id_shift_ = false;
+};
-#endif //AAPT2_DIFF_H
+} // namespace aapt